将基类转换为派生类[重复]

Posted

技术标签:

【中文标题】将基类转换为派生类[重复]【英文标题】:Convert base class to derived class [duplicate] 【发布时间】:2012-09-15 22:54:21 【问题描述】:

是否可以在 C# 中将基类对象显式转换为其派生类之一?目前认为我必须为我的派生类创建一个构造函数,该构造函数接受基类对象作为参数并复制属性值。我不太喜欢这个主意,所以我想尽可能避免它。

这似乎不应该工作(对象被实例化为新基,因此不应为派生类的额外成员分配内存)但 C# 似乎允许我这样做:

class BaseClass

  ... some stuff ...


class DerivedClass : BaseClass

    public bool MyDerivedProperty get; set; 



static void Main(string[] args)

    BaseClass myBaseObject = new BaseClass();
    DerivedClass myDerivedObject = myBaseObject as DerivedClass;

    myDerivedObject.MyDerivedProperty = true;

【问题讨论】:

你会在最后一行得到一个空引用异常。 已经在这里回答:***.com/questions/729527/… 您应该了解何时适合使用“as”与常规演员表。如果你在这里使用强制转换,C# 编译器会告诉你你在做什么是错误的。 我投票决定重新打开,因为标记的“重复”是一个完全不同的问题。这个问题是关于转换的,而“重复”的问题是关于铸造 最好最快的选择是使用 JsonConvert 你可以在原始问题上找到我的答案 【参考方案1】:

不,没有像你说的那样转换类的内置方法。最简单的方法是按照您的建议进行操作:创建一个 DerivedClass(BaseClass) 构造函数。其他选项基本上会出现以自动将属性从基础复制到派生实例,例如使用反射。

您使用as 发布的代码将会编译,我相信您已经看到了,但是当您运行它时会抛出一个空引用异常,因为myBaseObject as DerivedClass 将评估为null,因为它不是DerivedClass 的一个实例。

【讨论】:

【参考方案2】:

这是不可能的。但是你可以使用像AutoMapper这样的对象映射器

编辑

我想推荐一个更简单的对象映射器:TinyMapper。 AutoMapper 现在使用起来非常复杂。我不再使用它了。 TinyMapper 涵盖了大多数用例,而且更加简单且超级快速。

例子:

//In app startup
TinyMapper.Bind<Person, PersonDto>();

//Usage
var personDto = TinyMapper.Map<PersonDto>(person);

AutoMapper(我认为是旧版本)的示例,供仍然想使用它的人使用:

class A

    public int IntProp  get; set; 

class B

    public int IntProp  get; set; 
    public string StrProp  get; set; 

在 global.asax 或应用程序启动中:

AutoMapper.Mapper.CreateMap<A, B>();

用法:

var b = AutoMapper.Mapper.Map<B>(a);

它可以通过流畅的 API 进行配置。

【讨论】:

这很好用,但你必须先初始化它 AutoMapper.Mapper.Initialize(cfg => cfg.CreateMap()); AutoMapper中的DO和DONT参考官方2019年发布的AutoMapper Usage Guidelines 从 9.0 版开始不再支持 AutoMapper 静态 API。您将需要执行以下操作: var configuration = new MapperConfiguration(cfg => cfg.CreateMap(); ); var mapper = new Mapper(配置); var b = mapper.Map(a);然后最好将配置或映射器存储在依赖容器中。 这是很好的信息。我将此添加为切线:我正在寻找一种在 MVC 中使用 AutoMapper v 9.0+ 的方法。我最终在 Global.asax.cs 中创建了一个静态属性,并在 Application_Start 期间将配置的映射器分配给它。希望对可能没有考虑过这种方法的人有所帮助。在 .net Core 中,您可以只将映射器注入到您的控制器实例中,但这在“传统”.net 框架中不可用。 一般应避免使用 Automapper 之类的 Voodo。它使用反射来运行槽属性,并且与其他解决方案(如编写 a.prop1=b.pro1、a.pro2=b.prop2 等)相比,通常使用起来很昂贵【参考方案3】:

我找到了一种解决方案,并不是说它是最好的,但我觉得它很干净,不需要对我的代码进行任何重大更改。在我意识到它不起作用之前,我的代码看起来和你的很相似。

我的基类

public class MyBaseClass

   public string BaseProperty1  get; set; 
   public string BaseProperty2  get; set; 
   public string BaseProperty3  get; set; 
   public string BaseProperty4  get; set; 
   public string BaseProperty5  get; set; 

我的派生类

public class MyDerivedClass : MyBaseClass

   public string DerivedProperty1  get; set; 
   public string DerivedProperty2  get; set; 
   public string DerivedProperty3  get; set; 

上一个获取填充基类的方法

public MyBaseClass GetPopulatedBaseClass()

   var myBaseClass = new MyBaseClass();

   myBaseClass.BaseProperty1 = "Something"
   myBaseClass.BaseProperty2 = "Something else"
   myBaseClass.BaseProperty3 = "Something more"
   //etc...

   return myBaseClass;

在我尝试这个之前,这给了我一个无法投射的错误

public MyDerivedClass GetPopulatedDerivedClass()

   var newDerivedClass = (MyDerivedClass)GetPopulatedBaseClass();

   newDerivedClass.UniqueProperty1 = "Some One";
   newDerivedClass.UniqueProperty2 = "Some Thing";
   newDerivedClass.UniqueProperty3 = "Some Thing Else";

   return newDerivedClass;

我如下更改了我的代码,现在它似乎可以工作并且更有意义:

public MyBaseClass GetPopulatedBaseClass()

   var myBaseClass = new MyBaseClass();

   myBaseClass.BaseProperty1 = "Something"
   myBaseClass.BaseProperty2 = "Something else"
   myBaseClass.BaseProperty3 = "Something more"
   //etc...

   return myBaseClass;

public void FillBaseClass(MyBaseClass myBaseClass)

   myBaseClass.BaseProperty1 = "Something"
   myBaseClass.BaseProperty2 = "Something else"
   myBaseClass.BaseProperty3 = "Something more"
   //etc...

public MyDerivedClass GetPopulatedDerivedClass()

   var newDerivedClass = (MyDerivedClass)GetPopulatedBaseClass();

   newDerivedClass.UniqueProperty1 = "Some One";
   newDerivedClass.UniqueProperty2 = "Some Thing";
   newDerivedClass.UniqueProperty3 = "Some Thing Else";

   return newDerivedClass;

public MyDerivedClass GetPopulatedDerivedClass()

   var newDerivedClass = new MyDerivedClass();

   FillBaseClass(newDerivedClass);

   newDerivedClass.UniqueProperty1 = "Some One";
   newDerivedClass.UniqueProperty2 = "Some Thing";
   newDerivedClass.UniqueProperty3 = "Some Thing Else";

   return newDerivedClass;

【讨论】:

非常好!正是我想要的!谢谢:D 每次添加属性时,您都必须对其进行编辑。因此,对于其他阅读本文的人,我建议您考虑改用合成【参考方案4】:

您可以自己实现转换,但我不建议这样做。如果您想这样做以扩展现有对象的功能,请查看Decorator Pattern。

【讨论】:

【参考方案5】:

不,没有内置的转换。 您需要创建一个构造函数,就像您提到的那样,或其他一些转换方法。

另外,由于 BaseClass 不是 DerivedClass,myDerivedObject 将为 null,并且上面的最后一行将抛出 null ref 异常。

【讨论】:

【参考方案6】:

不,这是不可能的。唯一可行的方法是

static void Main(string[] args)

    BaseClass myBaseObject = new DerivedClass();
    DerivedClass myDerivedObject = myBaseObject as DerivedClass;

    myDerivedObject.MyDerivedProperty = true;

【讨论】:

这会引发 NullReferenceException,因此无法按说明工作 谢谢,其他答案没有说明如何投射 有时候,稍微反思一下,就可以避免重大问题。谢谢! 但这不起作用(正如 ahmed 所说,它会引发空引用异常) 这里没有发生转换。基类指针 (myBaseObject) 被简单地设置为 DerivedClass 的一个实例。从头到尾它仍然是一个 DerivedClass。

以上是关于将基类转换为派生类[重复]的主要内容,如果未能解决你的问题,请参考以下文章

通过 C++ 中的 std 迭代器将基类转换为派生

为啥以及何时使用多态性将基类指向 C++ 中的派生类 [重复]

我们可以将基类的私有成员继承到派生类的公共成员中吗?

与简单地创建派生类指针相比,将基类绑定到派生类有啥好处?

将基类传递给函数而不是派生一个

将基类的对象传递给派生类的引用函数