2009-12-04 67 views
4

我有这个简单的结构:1父母,和两个不同孩子。C#继承铸造一个孩子到另一个

public class Parent{} 

public class ChildA : Parent{} 

public class ChildB : Parent{} 

我有一个类型为ChildA的对象objA,我想将其转换为ChildB。我的幼稚方法说:

ChildA objA = new ChildA(); 

ChildB objB = (ChildB)objA; 

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

问候,卡斯帕

+1

@Chau:我认为使用儿童/儿童和父母类可能会产生误导。它给人的印象是孩子们彼此之间是可以投掷的。在你的例子中使用这种命名约定的事实可能是因为你有这样的倾向。但是我可能是错的:P – 2009-12-04 11:19:54

回答

10

,因为对象objA指的是这是不可能的一个ChildB。换一种方式,这里有你想要做一个例子:

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

他们都有一个共同的母公司 - System.Object - 但他们是完全不同的类别。如果您尝试从y读取,您希望发生什么?

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

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

ChildB ToChildB() 

进行适当的转换?

+0

好吧,回答一些问题:通过将ChildA转换为ChildB,我的想法是,常用变量将存活,并将未分配的变量设置为Null等。这正是我想要的,但由于您的回答,我选择了一种转换方法。 – Chau 2009-12-04 11:59:41

+1

@Chau:你的假设本来是非常不安全的 - 如果这些变量被要求使它成为一个有效的对象会怎样?转换的方法应该没问题:) – 2009-12-04 13:58:17

+0

@Jon:我相信你是完全正确的,但在我理想的世界中,它会工作得很好=) – Chau 2009-12-04 14:36:46

2

你不能因为ChildA不是ChildB(你只能从ChildA或ChildB上溯造型到家长,还是从家长到ChildB或ChildA垂头丧气,有没有这样的事情sidecasting在C#)

如果您想要使演员成为可能(一个可疑的努力,但是),你应该从ChildA到ChildB实现一个演员。

+0

向下转换也不起作用。假设你有: 父p =新父(); ChildA a =(ChildA)p; ChildA a =(ChildA)p; OR 父p = new ChildA(); ChildB b =(ChildB)p; 你不会期望它的工作! – 2009-12-04 19:08:56

+0

是的,它会在运行时失败,但它会编译。 – 2009-12-04 19:20:11

0

objA是不是的类型ChildB,即使它们都是父类的“子”。

0

你试图做的事情不会奏效。

您只能对其基类(Parent)或ChildA和ChildB可能实现的任何通用接口进行objA处理。

想象一下,ChildB定义了一种名为Foo的方法。你的objA实例如何处理称为Foo的人?显然它不能工作。

3

即使只有一个父对象,也不可能简单地抛出一个对象,因为它们可能有不同的接口。

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

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

在第一种情况下,你可以省略明确地定义类型转换,写就像这样:

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; } 
} 

和实施conversings运营商下面的代码将正常工作后

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; 
    } 
} 

使用(家长ClassA和ClassB的孩子的):

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

感谢您对Jons的更深入的解释,更一般的答案 - 尽管您的帖子似乎是平行的=) – Chau 2009-12-04 12:02:02

+0

@Chau欢迎您(% – bniwredyc 2009-12-04 12:19:14

0

ChildAChildB是不同的共享相同父代的类型。因此,您可以将ChildAChildB的实例作为基础,Parent,但由于它们是不同的类型,因此您不能将它们投射到另一个。

0

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

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

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

但我客串这只是一个例子,你说你为什么要实现这样的一个活生生的例子吗?

0

我很确定我想出了一种方法来模拟这个,这在某些时候可能是有用的。即:

  • 继承字典,或者IDictionary的,如果你需要其他基地的继承在两个位置
  • 存储属性实现它 - 字典和一个真正的现场
  • 保持第三布尔字段标志是否没有设置实际字段
  • 如果已设置实际字段,请使用实际字段
  • 如果没有,则取字典值(以及将字典值分配给实际字段并标记)
  • 如果没有字典值,充当虽然属性不存在
  • 添加一个构造函数字典,并使用从字典

值现在,您可以乘坐CatLikeObject从这个基地继承填充此类,并通过使用构造函数(将猫转换为字典),生成一个相同的DogLikeObject(它会吠叫而不是喵,但仍称为“Puss”)。

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

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; 

}