【问题标题】:C#: Resolving Invalid Cast Exception Between an Inherited Class and Its BaseC#:解决继承类与其基类之间的无效强制转换异常
【发布时间】:2010-12-26 02:48:43
【问题描述】:

我有两个类,名为 Post 和 Question。问题定义为:

public class Question : Post
{
//...
}

我的 Question 类没有覆盖 Post 的任何成员,它只是表达了其他一些成员。


我想要完成的事情

我有一个 Post 类型的对象,它的成员被填充。现在,我想将其转换为问题,以便为其他少数成员添加值。

这是我当前的代码,使用显式强制转换:

Post postToQuestion = new Post();

//Populate the Post...

Question ques = (Question)postToQuestion; //--> this is the error!

//Fill the other parts of the Question.

问题

我收到 InvalidCastException。我做错了什么?

【问题讨论】:

    标签: c# .net oop inheritance casting


    【解决方案1】:

    问题是您不能从父级转换为子级。您可以为将父类作为参数的子类创建一个构造函数: 问题 ques = new Question(myPost);

    您还可以使用隐式运算符来简化执行此操作: 问题 ques = myPost;

    http://www.codeproject.com/KB/cs/Csharp_implicit_operator.aspx

    编辑: 实际上,我只是尝试为您键入一个演示来执行隐式运算符:

    class Question : Post
    {
        public Question()
        {
            //...
        }
    
        public Question(Post p)
        {
            // copy stuff to 'this'
        }
    
        public static implicit operator Question(Post p)
        {
            Question q = new Question(p);
            return q;
        }
    }
    

    但显然 C# 不允许您使用基类进行隐式转换。

    【讨论】:

    • 我刚刚尝试使用您的隐式运算符示例,但我收到编译器错误 CS0553: 'User-defined conversions to a base class of an value is not allowed'。
    • 是的,我在发布后就注意到了。在我的帖子底部,有一篇文章的链接解释了您遇到的相同问题,并展示了他如何解决该问题的示例。
    【解决方案2】:

    此时发布不是问题,CLR 的抱怨是正确的。您可以将问题向上发送,但反之亦然。现在,如果您有一个对您知道是问题的帖子的高级引用,您可以像这样沮丧:

    public Post Post 
    {
        set
        {
            if (value is Question)
            {
                question = (Question)value;
            }
        }
    }
    

    但即使这是a code smell

    但我认为你想要完成的事情可以在没有类转换的情况下实现,或者根本不需要继承。遵循古老的"favor encapsulation over inheritance" 原则,为什么不直接将 Post 对象包装到您的 Question 对象中,例如:

    public class Question 
    {
        Post post;
        public Question(Post post)
        {
            this.post = post;
        }
    }
    

    假设您已经为 Post 的相关成员定义了属性,而不是

    Question ques = (Question)post;
    

    你应该有

    Question ques = new Question(post);
    

    【讨论】:

    • 这个加上接口继承将使它成为最直接的实现。
    • -1 用于使用 java 样式 setBlah,这是 .net 中的属性
    • 另外,它是“is”,而不是“instanceof”
    • 抱歉,Java 在大脑上和 NetBeans 近在咫尺——原理是相同的。我已经为 C# 修复了。
    【解决方案3】:

    进行投射不会更改您正在投射的对象 - 因此它无法将缺少的“问题”成员添加到您的“帖子”对象中。恐怕您只需要创建一个新的“问题”对象,然后将您感兴趣的成员从“帖子”复制到“问题”。

    请注意,以其他方式进行转换,从“问题”到“帖子”,可以正常工作,因为您可以将问题视为帖子,而无需更改它 - 所有必填字段都已存在。

    【讨论】:

      【解决方案4】:

      如果您想更改类型,您需要编写代码,或者有时可以序列化。强制转换不会改变类型(除非已经编写了自定义运算符)。

      最简单的选项是首先将其创建为正确的类型:

      Post post = new Question();
      

      或者,添加转换运算符或其他方法以从帖子中创建Question

      class Question {
          public Question(Post post) {
              this.Author = post.Author;
              this.Body = post.Body;
              // ...
          }
      }
      ...
      Question question = new Question(post);
      

      您还可以使用其他技巧,例如基于反射的属性副本或序列化;例如,使用MiscUtil:

      Question question = PropertyCopy<Question>.CopyFrom(post);
      

      protobuf-net(需要一些额外的序列化属性):

      Question question = Serializer.ChangeType<Post,Question>(post);
      

      【讨论】:

        【解决方案5】:

        你可以这样做吗:

        public Question(Post P) : base(p) {...}
        
        class Post 
        {
            public Post(Post P)
            {
                 populate(P.ID);
            }
        
            void populate(int ID)
            {
                 // load from DB, or however it happens
            }
        }
        

        ...如果您仍然从数据存储中实例化 Post?

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多