2009-12-04 56 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; 

}