2016-12-29 105 views
2

我有一個泛型基類和兩個從基類派生的類。我想用對象工廠創建這種派生類。但我不能用泛型基類來做到這一點。我可以用Java這樣做,沒有任何問題。我也用c#解決了這個問題,裝箱和拆箱。什麼是正確的方法來做到這一點?C#泛型基多態性

public abstract class Base<T> { 
    public abstract T Value { 
     get; 
     set; 
    } 
} 

public class Derived1 : Base<int> { 
    int value; 

    public override int Value { 
     get { 
      return value; 
     } 
     set { 
      this.value = value; 
     } 
    } 
} 

public class Derived2 : Base<float> { 
    float value; 

    public override float Value { 
     get { 
      return value; 
     } 
     set { 
      this.value = value; 
     } 
    } 
} 

public class Factory { 
    public Base create(int type) { 
     switch(type) { 
      case 1: 
       return new Derived1(); 
      case 2: 
       return new Derived2(); 
     } 
    } 
} 

謝謝!

解決:據我所知,因爲任何接口不會有通用的方法,他們也不會幫助。只有解決方案是將值裝入對象中。這是我的解決方案。

public abstract class Base { 
    public abstract object Value { 
     get; 
     set; 
    } 
} 

public class Derived1 : Base { 
    int value; 

    public override object Value { 
     get { 
      return value; 
     } 
     set { 
      this.value = (int) value; 
     } 
    } 
} 

public class Derived2 : Base { 
    float value; 

    public override object Value { 
     get { 
      return value; 
     } 
     set { 
      this.value = (float) value; 
     } 
    } 
} 

public class Factory { 
    public Base create(int type) { 
     switch(type) { 
      case 1: 
       return new Derived1(); 
      case 2: 
       return new Derived2(); 
      default: 
       return null; 
     } 
    } 
} 

現在我可以將所有派生的對象視爲基礎對象。

+2

我有點失落。你在那裏有什麼問題? – TyCobb

+0

只要你不介意在爲你的Factory添加支持的類型時不介意繼續增加一個int值賦值,這就足夠了。 ......除了@ PeterA.Schneider指出,你必須有一個非通用的'Base '返回。 – IAbstract

+1

@TyCobb我猜你不能像這樣使用'Base';你必須在「基地」或「基地」之間做出決定,這種做法會破壞目的。 –

回答

2

您將不得不有一個非通用的Base<T>返回類型; 您可以考慮使用TypeCode

public class Factory { 
    public Base<T> create<T>() { 
     var typeCode = Type.GetTypeCode(typeof(T)); 
     switch (typeCode) 
     { 
      case TypeCode.Empty: 
       break; 
      case TypeCode.Object: 
       break; 
      case TypeCode.DBNull: 
       break; 
      case TypeCode.Boolean: 
       break; 
      case TypeCode.Char: 
       break; 
      case TypeCode.SByte: 
       break; 
      case TypeCode.Byte: 
       break; 
      case TypeCode.Int16: 
       break; 
      case TypeCode.UInt16: 
       break; 
      case TypeCode.Int32: // Derived1 : Base<int> 
       return new Derived1(); 

       break; 
      case TypeCode.UInt32: 
       break; 
      case TypeCode.Int64: 
       break; 
      case TypeCode.UInt64: 
       break; 
      case TypeCode.Single: // Derived2 : Base<float> 
       return new Derived2(); 

       break; 
      case TypeCode.Double: 
       break; 
      case TypeCode.Decimal: 
       break; 
      case TypeCode.DateTime: 
       break; 
      case TypeCode.String: 
       break; 
      default: 
       throw new ArgumentOutOfRangeException(); 
     } 
    } 
} 

...此外,如果你使用的接口,你可以 「隱藏」 <TypeParam>從返回:

public interface IBase { 
    // properties/methods 
} 

然後:

public abstract class Base<T> : IBase { 
     // properties/methods 
} 

然後:

public class Factory { 
    public IBase create<T>() { 
     // logic 
    } 
} 

現在,對於返回Value有三種選擇:(1)堅持執行而不需要接口IBase; (2)在界面中使用dynamic返回類型,或; (3)方框您所做的值爲object

注意:註銷我的頭頂,未經測試。

// 1. implementation without the interface  
public abstract class Base<T> { 
    public abstract T Value {get; set;} 
} 

// 2. implementation with IBase 
public interface IBase { 
    public dynamic Value {get; set;} 
} 

public abstract Base<T> : IBase { 
    public abstract dynamic Value {get; set;} 
} 
+1

對TypeCode的使用感覺不錯,而不是大量的'if(typeof(T)...'檢查+1 – TyCobb

+0

接口的使用在這裏也是一個更清潔的方法,也許如果我到家時變得不靈活我會補充說。 – IAbstract

+0

@IAbstract是的,我會很感謝。可能是我不能很好地解釋。工廠之後,我想訪問每個對象的Value propery,無論它的類型如何:例如:Base d1 = new Factory ).Create(1); d1.Value應該返回整型值 –

0

這裏是實現你想要什麼,但工廠的調用者需要知道所創建的類型中的一種方式。我還將派生類中的屬性更改爲自動屬性,因爲您沒有對它們做任何特殊處理,但是如果您願意,可以將它們更改回去。

public abstract class Base<T> { 
    public abstract T Value 
    { 
     get; 
     set; 
    } 
} 

public class Derived1 : Base<int> { 
    public override int Value { get; set; } 
} 

public class Derived2 : Base<float> { 
    public override float Value { get; set; } 
} 

public class Factory { 
    public Base<T> Create<T>(int type) { 
     switch(type) { 
     case 1: 
     return new Derived1() as Base<T>; 
     case 2: 
     return new Derived2() as Base<T>; 
     } 

     return null; // or whatever you want to do 
    } 
} 

這裏的用法:

var f = new Factory(); 
var one = f.Create<int>(1); 
var two = f.Create<float>(2); 

就像我提到的工廠的調用者需要創建的類型有一定的瞭解,因爲這將失敗:

var f = new Factory(); 
var one = f.Create<int>(2); // <-------- Changed from 1 to 2 
var two = f.Create<float>(1); // <-------- Changed from 2 to 1 

您可以隨時從工廠拋出異常來解釋爲什麼你不能創建請求的類型,以便調用者可以採取適當的步驟。

+0

可能是我解釋不好。工廠之後,我想訪問Value propery每個對象的類型,例如:Base d1 = new Fact ORY()創建(1)。 d1.Value應該返回整數值。 –

+0

它現在會這樣做'int value = one.Value' – CodingYoshi