C#继承将一个子节点转换为另一个子节点

时间:2009-12-04 11:04:19

标签: c# inheritance casting

我有这个简单的结构:1个父母和2个不同的孩子。

public class Parent{}

public class ChildA : Parent{}

public class ChildB : Parent{}

我有一个ChildA类型的对象objA,我想将其强制转换为ChildB。我天真的做法说:

ChildA objA = new ChildA();

ChildB objB = (ChildB)objA;

但这不是直接可能的 - 为什么?这是因为我需要实现一些功能还是因为我的天真方法是错误的?

问候,卡斯帕

8 个答案:

答案 0 :(得分:10)

这是不可能的,因为objA引用的对象是而不是 a ChildB。换句话说,这是你要做的事情的一个例子:

 string x = "hi";
 FileStream y = (FileStream) x;

他们都有一个共同的父母 - System.Object - 但他们是完全不同的类。如果您尝试阅读y

,您会发生什么?

假设您的ChildB类型有一些特定于该类型的字段 - 您希望该字段的值在投射objA后会是什么?

为什么你想假装ChildA实际上是ChildB?你可以在父类中添加一个你想要的方法吗?在ChildA中添加方法,如下所示:

ChildB ToChildB()

执行适当的转换?

答案 1 :(得分:3)

即使有一个父对象,也不可能简单地转换一个其他类型的对象,因为它可能有不同的接口。

您需要实现ChildA(或ChildB)的显式或implitic运算符。

class ClassA
{
    public string Property1 { get; set; }
}

class ClassB
{
    public string Property2 { get; set; }

    public static implicit operator ClassB(ClassA classA)
    {
        return new ClassB() { Property2 = classA.Property1 };
    }
}

class ClassA
{       {
    public string Property1 { get; set; }

    public static explicit operator ClassB(ClassA classA)
    {
        return new ClassB() { Property2 = classA.Property1 };
    }
}

class ClassB
{
    public string Property2 { get; set; }
}

在实现转换后,运算符跟随代码将正常工作:

var a = new ClassA() {Property1 = "test"};
ClassB b = (ClassB)a;
Console.WriteLine(b.Property2); // output is "test"

在第一种情况下,您可以省略明确的类型转换并像这样写:

var a = new ClassA() {Property1 = "test"};
ClassB b = a;

最后,如果您只想同步父类的属性,可以直接在父级中编写转换器:

class Parent
{
    public string ParentProperty { get; set; }
    public static T1 Convert<T1>(Parent obj) where T1 : Parent, new()   
    {
    var result = new T1();
    result.ParentProperty = obj.ParentProperty;
    return result;
    }
}

使用(Parent的ClassA和ClassB子级):

var a = new ClassA();
a.ParentProperty = "test";
ClassB b = Parent.Convert<ClassB>(a);
Console.WriteLine(b.ParentProperty); // output is "test"

答案 2 :(得分:2)

你不能因为ChildA不是ChildB(你只能从ChildA或ChildB转发到Parent,或者从Parent转发到ChildB或ChildA,在C#中不存在侧播)

如果你想使演员成为可能(这是一个值得怀疑的努力,但你应该),你应该实现从ChildA到ChildB的演员操作。

答案 3 :(得分:0)

objA是ChildB类型的 NOT ,即使两者都是来自Parent类的“children”。

答案 4 :(得分:0)

你要做的事情是行不通的。

你只能对它的基类(Parent)或者ChildA和ChildB可能实现的任何公共接口进行objA。

想象一下,ChildB定义了一个名为Foo的方法。你的objA实例如何处理调用Foo的人?显然它不起作用。

答案 5 :(得分:0)

ChildAChildB是共享同一父级的不同类型。因此,您可以将ChildAChildB的实例视为其基础Parent,但由于它们是不同类型,因此您无法将其中一个转换为另一个。

答案 6 :(得分:0)

正如其他人所说,ChildA不是ChildB。如果ChildA和B具有相同的属性/功能,那么您应该这样做:

public class Parent{}
public class Child : Parent{}

Child objA = new Child();
Child objB = objA;

但我猜这只是一个例子,你有一个真实的例子,为什么你想要达到这样的目的?

答案 7 :(得分:0)

我非常确定我已经想出了一种模拟这种方法的方法,这在某些方面可能很有用。即:

  • 继承自Dictionary或IDictionary,并在需要其他基本继承时实现它
  • 将属性存储在两个位置 - 字典和真实字段
  • 保留第三个布尔字段,标记实际字段是否已设置
  • 如果已设置真实字段,请使用真实字段
  • 如果还没有,请取字典值(以及将其分配到真实字段并标记)
  • 如果没有字典值,就好像该属性不存在
  • 添加一个构造函数,该构造函数接受一个Dictionary并使用Dictionary
  • 中的值填充它

现在你可以使用继承自这个基类的CatLikeObject,并使用构造函数(将cat转换为Dictionary),生成一个相同的DogLikeObject(它将吠叫而不是喵喵,但仍被称为&#34; Puss& #34;。)

缺点?属性占用了更多的空间,并且很多类型的安全性转移到运行时,更不用说可能存在的任何性能损失(并且肯定会有一些)。好处?如果您需要暂时将猫视为狗,您可以。

public class CSharepointStoredResults : Dictionary<string, object>
{

    public CSharepointStoredResults(Dictionary<string, object> SourceDict = null) 
    {
        // Populate class dictionary from passed dictionary. This allows for some degree of polymorphism sideways.
        // For instance it becomes possible to treat one CSharepointStoredResults as another (roughly like treating
        // a cat as a dog
        foreach (string key in SourceDict.Keys) { this.Add(key, SourceDict[key]); }
    }

    public Type MyType 
    {
        get {
            if (!__MyType && !this.ContainsKey(bObj.GetPropertyNameFromExpression(() => this.MyType)))
            {
                // Neither a dictionary nor a field set
                // return the field
            }
            else if (!__MyType)
            {
                // There is a dictionary entry, but no volatile field set yet.
                __MyType = true;
                _MyType = this[bObj.GetPropertyNameFromExpression(() => this.MyType)] as Type;
            }
            else 
            {
                // Volatile value assigned, therefore the better source. Update the dictionary  
                this[bObj.GetPropertyNameFromExpression(() => this.MyType)] = _MyType;
            }
            return _MyType;
        }
        set {
            // Verify the value is valid...
            if (!(value.IsInstanceOfType(typeof(CSharepointStoredResults))))
                throw new ArgumentException("MyType can only take an instance of a CSharePointResults object");
            _MyType = value;
            this[bObj.GetPropertyNameFromExpression(() => this.MyType)] = value;
        }
    }
    private volatile Type _MyType;
    private volatile bool __MyType;

}