将基类型转换为继承类型而不进行初始化

时间:2015-01-27 04:47:44

标签: c# oop

无论如何都要将对象直接转换为继承类型?

class Base
{
    void Process()
    {
    Base obj = new Derived1();
    }
}

class Derived1 : Base
{
}

class Derived2 : Base
{
}

如果不初始化或创建obj的新实例,我如何将对象Derived2转换为Derived2类型?

3 个答案:

答案 0 :(得分:1)

从您的示例中,您无法将对象从Derived1更改为Derived2。您的代码正在将Derived1的新实例创建为对象类型Base这很好,因为Derived1将具有与Base相同的签名。但是BaseDerived1没有相同的签名,您无法转换为继承类型。虽然Derived1的基类为Base,但不能确保签名相同。

在使用implicitexplicit运算符的用户定义转换中也是如此。您无法从基类编写自己的转换,因为这会提供多个有效的转换。

Base转换为Derived2(或其他派生类)的唯一方法是创建Derived2的新引用,并将属性复制到此新类。然而,在现实世界中,这不仅耗费时间,而且通常是您设计过程中的一个缺陷。

在大多数情况下,您调用一个返回特定类型对象的方法。例如,Base(实际上没有方法或属性)应该定义对象的行为方式以及该对象的公共属性和方法。 Derived1Derived2可以在此共同签名的基础上构建。您的设计非常灵活,但在通常情况下,您可以基本上重写您的对象,类似于下面的示例。您会注意到不需要转换。

首先定义基类的接口。虽然这不是必需的,但在类之间增加了一致性(同样不是必需的)。

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继承自BaseBase继承了接口IBaseBase已在方法和属性上定义了接口IBasevirtual关键字。这意味着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转换为DerivedDerived2转换为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)

一个很好的类比,您的基数可以归类为水果Derived1Derived2可以是 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)