无论如何都要将对象直接转换为继承类型?
class Base
{
void Process()
{
Base obj = new Derived1();
}
}
class Derived1 : Base
{
}
class Derived2 : Base
{
}
如果不初始化或创建obj
的新实例,我如何将对象Derived2
转换为Derived2
类型?
答案 0 :(得分:1)
从您的示例中,您无法将对象从Derived1
更改为Derived2
。您的代码正在将Derived1
的新实例创建为对象类型Base
这很好,因为Derived1
将具有与Base
相同的签名。但是Base
与Derived1
没有相同的签名,您无法转换为继承类型。虽然Derived1
的基类为Base
,但不能确保签名相同。
在使用implicit
或explicit
运算符的用户定义转换中也是如此。您无法从基类编写自己的转换,因为这会提供多个有效的转换。
将Base
转换为Derived2
(或其他派生类)的唯一方法是创建Derived2
的新引用,并将属性复制到此新类。然而,在现实世界中,这不仅耗费时间,而且通常是您设计过程中的一个缺陷。
在大多数情况下,您调用一个返回特定类型对象的方法。例如,Base
(实际上没有方法或属性)应该定义对象的行为方式以及该对象的公共属性和方法。 Derived1
和Derived2
可以在此共同签名的基础上构建。您的设计非常灵活,但在通常情况下,您可以基本上重写您的对象,类似于下面的示例。您会注意到不需要转换。
首先定义基类的接口。虽然这不是必需的,但在类之间增加了一致性(同样不是必需的)。
interface IBase
{
string Name { get; set; }
void DoWork();
}
这只是定义了一个property
和一个method
的界面。接下来将您的简单基类编写为:
class Base : IBase
{
string name = "Base Class: ";
public virtual string Name
{
get { return this.name; }
set { this.name = value; }
}
public virtual void DoWork()
{
//Base class does no work...
}
}
基类Base
继承自IBase
,并从接口实现方法和属性。在此示例中,我还将属性和方法标记为virtual
https://msdn.microsoft.com/en-us/library/9fkccyh4.aspx,因此任何继承自Base
的类都可以覆盖该成员。因此,在此类中设置名称(使用支持字段)并实现了DoWork
方法,该方法实际上什么都不做。
接下来,我定义了另一个继承自Derived1
的类Base
。
class Derived1 : Base
{
public override void DoWork()
{
this.Name = "Derived 1 did some work.....";
}
}
现在Derived1
继承自Base
,Base
继承了接口IBase
。 Base
已在方法和属性上定义了接口IBase
和virtual
关键字。这意味着Derived1
可能override
Base
的成员(但也没有)... Derived1
类现在将覆盖方法DoWork
并设置字符Derived 1 did some work....
到属性Name
。
然后,我们可以定义从Base
继承为Derived2
class Derived2 : Base
{
string name;
public override string Name
{
get { return this.name; }
set { this.name = value; }
}
public override void DoWork()
{
this.Name = base.Name + " - Derived 2 did some work.....";
}
}
就像新的Derived2
继承自Base
并且在这个实例中覆盖属性Name
和方法DoWork
之前一样,但是在这个例子中,确实有效方法是使用Name
关键字从base
类访问属性base
。这基本上将Derived2
的名称设置为基类Base
的名称并追加' - 衍生2做了一些工作.....'。
现在这实际上没有回答您的问题,因为您无法将Derived2
转换为Derived
或Derived2
转换为Base
但是提供了构建您的类的签名。
现在要在现实世界中使用它,我们(如前所述)执行方法或接收返回我们的对象类型的事件。
class Program
{
static void Main(string[] args)
{
var baseObj = getBase();
baseObj.DoWork();
Console.WriteLine("Base Name:" + baseObj.Name);
var d1 = getDerived1();
d1.DoWork();
Console.WriteLine("Derived 1 Name:" + d1.Name);
var d2 = getDerived2();
d2.DoWork();
Console.WriteLine("Derived 2 Name:" + d2.Name);
Console.ReadKey();
}
static IBase getBase()
{
return new Base();
}
static IBase getDerived1()
{
return new Derived1();
}
static IBase getDerived2()
{
return new Derived2();
}
}
如下所示,我们有3个返回IBase
实例的方法,这些实例都将具有匹配的签名,因为它们都从同一个接口继承。但是在每种方法中,我们都在构建不同类型的新对象。当为每个对象执行方法DoWork
时,将在每个对象类型上调用基础方法。
现在,这可能是一种长篇大论,说它无法完成,但希望这能告诉您如何通过修改对象的定义来实现所需的目标。
啦啦队
答案 1 :(得分:0)
你无法做到这一点,只是因为Derived1
不是Derived2
(Derived1!= Derived2)。
一个很好的类比,您的基数可以归类为水果,Derived1
和Derived2
可以是 Apple 和香蕉即可。在更大的背景下,是的,他们与水果的分类相同。但你不能把香蕉变成苹果,反之亦然。
你可以做的是创建你自己的转换器,这是我为你开始创建的一个快速模型。
public static class ObjectConverter<T>
{
public static TTo Convert<TFrom, TTo>(TFrom value)
where TFrom : T
where TTo : T, new()
{
TTo result = new TTo(); // creates an instance of the target type
var baseProperties = value.GetType().GetProperties() // gets all properties
.Where(x => x.DeclaringType == typeof(T)); // based on target type
foreach (var prop in baseProperties)
{
prop.SetValue(result, prop.GetValue(value)); // sets value to the target
}
return result;
}
}
并且像这样消费。
Base item = new Derived1(); // base object
item.Age = 18; // properties existing on the base
item.Name = "Sasha";
Derived2 convertedItem = ObjectConverter<Base>.Convert<Derived1, Derived2>(item as Derived1);
答案 2 :(得分:0)