将子对象强制转换为父类型以进行序列化

本文关键字:类型 序列化 父类 对象 转换 | 更新日期: 2023-09-27 18:22:12

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

public class Parent 
{
    public string name{ get; set; } 
}
public class Child : Parent { }
var myClass = new Child();
(Parent)myClass;

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

还有别的办法吗?

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

将子对象强制转换为父类型以进行序列化

您没有将强制转换分配给任何内容。

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

编辑-我想你误解了选角的工作原理。假设Parent有一个virtual方法DoStuff(),该方法在Child中被重写。即使将myClass强制转换为Parent,它也将运行ChildDoStuff方法。不管怎样,Child就是Child,而且永远都是Child,即使你投了它

如果你试图将它传递给一个接受Parent对象的方法,你不必强制转换它。它已经是Parent了,因为它是Child

我想我们错过了什么。你想搭讪什么?什么不起作用?

应该可以。

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

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

编辑根据您留下的一些评论,我相信您误解了大多数编程语言的一个基本方面。它是这样的:对象的类型不能更改。实例化为Child对象的对象将始终是Child对象

投射不会更改对象的类型。铸造改变了程序其余部分"看到"对象的方式。如果您愿意的话,它会更改对象的界面。因此,如果将Child对象强制转换为Parent类型,程序的其余部分会认为它处理的是Parent类型,但实际上是处理的是一个Child类型,用一个非常糟糕的比喻来说,就是披着父对象的衣服。

简言之,铸造并没有做到你认为的那样。

问题是xml序列化程序将具有子类型的对象序列化为根元素。我真的不想一直通过我的目标类型向下进入串行器。有更好的方法吗Jules

我没有太多地使用序列化,但我的猜测是,您将需要更改"的定义;我如何序列化自己";在子元素中,将自己写成父元素。

如果你想实际拥有一个"的实例;父";然后你需要创建一个新的父级,并将所有值从子级复制到该父级(如果你有很多,我不会这么做,但如果你没有那么多,那应该不会有问题)。

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

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

我在这里迟到了大约五年,但是。。。

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

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

CreateMap<Child, Parent>();

然后,在代码中的任何一点,您都可以执行以下操作:

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

并且您的parent对象将是一个纯Parent,不具有任何child对象属性。

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

您可以使用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");

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

此外,不能仅以演员阵容开始一行。你可以写例如

Parent p = (Parent)myClass;

刚刚遇到了这个问题的变体,我认为我得到了一个基于非序列化的解决方案。

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

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

这样B.GetType()看起来总是像A.GetType(

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

然后,在我的一个特殊类上,我想让它看起来像它的父类,我会覆盖它来返回这个。GetType().BaseType.Name

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

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

我最初的代码是这样的:

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);
}