【问题标题】:Cast child object to parent type for serialization将子对象转换为父类型以进行序列化
【发布时间】:2022-01-18 10:30:26
【问题描述】:

我需要能够将子对象的实例转换为其父对象的实例。

public class Parent 
{
    public string name{ get; set; } 
}

public class Child : Parent { }

var myClass = new Child();

(Parent)myClass;

上面的转换似乎不起作用,并且对象仍然具有子类型序列化时

还有其他的投射方式吗?

我只使用子类进行验证——出于序列化原因,我需要子类具有父类的类型。

【问题讨论】:

  • 我需要这样做,因为我只使用子类进行验证。出于序列化原因,我需要孩子只有父母类型。
  • var castClass = (Parent)myClass castClass 在此行之后仍有子类型。
  • 这是一个有效的问题,并且序列化程序暴露了一个不容易立即显而易见的 C# 行为,即可以将对象作为基本类型引用,但将其转换为这样实际上并不会改变它对象或其类型。这在序列化之外的大多数情况下都可以正常工作,但它肯定不仅仅是序列化。 +1 询问我正在寻找的问题。但是,稍微修改一下您的问题会使其更有用。
  • 几乎要问这个问题了,虽然我的是vb.net。对这个问题 +1,因为Servy's answer 是我在每次尝试中都错过的(甚至尝试过序列化,发现它太重了)所以 +1 对 Matt Grande 的评论,因为这个问题值得更精确 关于这个问题(序列化 类的使用)但是,Servy 的答案不仅仅是关于序列化(第二段不包括引用不是 ;))谢谢,我现在可以将我的(父)类与 200+ ReadOnly 属性一起使用。

标签: c# serialization casting


【解决方案1】:

你没有将演员分配给任何东西。

var myClass = new Child();
Parent p = (Parent)myClass;

编辑 - 我认为您误解了投射的工作原理。假设 Parent 有一个 virtual 方法,DoStuff()Child 中被覆盖。即使您将myClass 转换为Parent,它也会运行ChildDoStuff 方法。不管怎样,ChildChild,并且永远是 Child,即使你施放它。

如果您尝试将其传递给接受Parent 对象的方法,则不必强制转换它。由于是Child,它已经是Parent

我认为我们缺少一些东西。你想达到什么目的?什么不工作?

【讨论】:

    【解决方案2】:

    应该可以的。

    但我怀疑从您编写代码的方式来看,您没有在新变量中捕获演员表对象?试试这个:

    var myClass = new Child()
    var myClassAsParent = (Parent)myClass;
    // myClassAsParent still has the type "Child", but can be accessed as if it were a Parent.
    

    编辑 根据您离开的一些 cmets,我相信您误解了大多数编程语言的基本方面。就是这样:对象的类型不能改变。实例化为Child 对象的对象将始终是Child 对象

    铸造不会改变对象的类型。强制转换改变了程序其余部分“看到”对象的方式。如果您愿意,它会更改对象的接口。因此,如果您将 Child 对象转换为 Parent 类型,程序的其余部分会认为它正在处理 Parent 类型,但它真的处理的是 Child 类型,用一个非常糟糕的比喻,穿着父母的衣服。

    简而言之,Casting 不会像您认为的那样做。

    【讨论】:

    • 是一个不完整的样本。这不起作用 var myClassAsParent = (Parent)myClass;
    • Randolpho:您能否提供一些额外的信息或一篇文章,我可以在其中了解更多关于“对象的类型不能改变..”的逻辑以及它与强制转换的关系。谢谢!
    【解决方案3】:

    问题是 xml 序列化程序将具有子类型的对象序列化为 根元素。我真的不想一直传递我的目标类型 进入序列化器。有没有更好的办法? – 朱尔斯

    我没有过多地使用序列化,但我的猜测是您将需要更改子元素中“我如何序列化自己”的定义,以便将自己写出来,就好像它是父元素一样。

    如果你想真正拥有一个“Parent”的实例,那么你需要创建一个 new Parent 并将所有值从 Child 复制到该 Parent (我不会这样做如果你有很多,但如果你没有那么多那么这应该不是问题)。

    最简单的方法是在 Parent 中创建一个复制构造函数。这将是一个构造函数,它将 Parent 作为参数并将值(在本例中为 Name,我假设您可能已经省略了其他值)从参数复制到自身。

    然后您可以创建一个新的 Parent,将 Child 作为参数传入(因为 Child 是 Parent,因此不需要强制转换/转换),它会输出 Parent 的实际实例。

    【讨论】:

      【解决方案4】:

      我在这里晚了大约五年,但是......

      您可以使用AutoMapper 来解决您的问题。

      只需定义父类和子类之间的映射。最简单的地图就可以了。在您定义映射的类中:

      CreateMap<Child, Parent>();
      

      然后,在您的代码中的任何位置,您都可以:

      Child child = new Child();
      Parent parent = Mapper.Map<Parent>(child);
      

      您的parent 对象将是一个纯Parent,没有child 对象属性。

      正如其他人所说,强制转换对象将保留其类型。这只改变了指针。但是 AutoMapper 会创建一个目标类型的新实例,并将值从参数复制到目标类型的实例,按名称匹配属性。

      【讨论】:

        【解决方案5】:

        你可以使用 as 操作符...好处是不会抛出异常,如果“强制转换”失败,你可以检查 null。

        public class Parent 
        {
         public string name{get;set;} 
        }
        
        public class child : Parent{}
        
        var myClass = new Child()
        Parent foo  = myClass as Parent
        if ( foo == null ) Debug.WriteLine("foo is NOT of type Parent");
        

        【讨论】:

          【解决方案6】:

          如果ParentChild 的超类,那么Child 自动也是Parent(包含`Parent 的所有属性和方法)并且您不需要强制转换。

          另外,你不能只用演员表开始一行。你可以写例如

          Parent p = (Parent)myClass;
          

          【讨论】:

            【解决方案7】:

            刚刚解决了问题的一个变体,我想我有一个基于非序列化的解决方案。

            和 OP 一样,我有从 A 类继承的 B 类,我需要 B.GetType().Name 来返回,就好像它是 A 类一样。

            在 B 类上,您需要重写 GetType() 以返回 .GetType().BaseType

            这样 B.GetType() 将永远看起来像 A.GetType()

            由于这相当繁重,而且我的所有类都继承自我自己的标准基类,因此我将向返回 this.GetType().Name 的基类添加一个名为 TypeName 的属性

            然后在我想要看起来像它的父级的一个特殊类上,我将覆盖它以返回 this.GetType().BaseType.Name

            然后在我的代码中,当我需要对类的类型名称进行特殊“屏蔽”时,我将直接引用 .TypeName 而不是执行 .GetType().Name。鉴于我只使用 .GetType () 在我需要忽略这个子类的一个区域中,它对我自己的使用来说相当干净。

            【讨论】:

              【解决方案8】:

              我遇到了同样的问题并想出了以下解决方案:

              我的初始代码是这样的:

              public class Person
              {
                  public string Name { get; set; }
              
                  public Person() {};
                  public Person( Person rhs ) 
                  {
                      Name = rhs.Name;
                  }
              }
              
              public class Customer : Person
              {
                  private string m_role = "Customer";
                  public string Role { get m_role; }
              
                  public Customer() : base();
              }
              
              public class Employee : Person
              {
                  private string m_role = "Employee";
                  public string Role { get m_role; }
              
                  public Employee() : base();
              }
              

              当我尝试将 Person 对象投射给客户时,出现“投射失败”错误

              我决定修改 Child 的复制构造函数,而不是追求强制转换的想法,因此:

              public class Customer : Person
              {
                  private string m_role = "Customer";
                  public string Role { get m_role; }
              
                  public Customer() : base();
                  public Customer( Person per ) : base( per);
              }
              
              public class Employee : Person
              {
                  private string m_role = "Employee";
                  public string Role { get m_role; }
              
                  public Employee () : base();
                  public Employee ( Person per) : base( per);
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2018-03-22
                • 1970-01-01
                • 1970-01-01
                • 2011-11-15
                • 1970-01-01
                • 2021-10-06
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多