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