2017-04-13 117 views
1

我以泛型類型開始,並且堅持使用我的項目。也許我不太瞭解泛型。解釋已經插入。基本上,我需要實現DO()方法,但我不知道如何解決<T2>:將泛型類型轉換爲子類型

public abstract class MyGenericClass<T> { } 

    public class MyGenericClass<T, T2> : MyGenericClass<T> 
    { 
     public Expression<Func<T, T2>> expression; 

     public MyGenericClass(Expression<Func<T, T2>> expression) 
     { 
      this.expression = expression; 
     } 
    } 

    public class MyClass<T> 
    { 
     // I need to mantain a list of my generic class for later use. 
     // I don't know T2 at this point. 
     // So I Chose to use Inheritance as a workaround (MyGenericClass<T> and MyGenericClass<T, T2>). 
     // Maybe it's not a good solution but I counldn't find out other solution. 
     public List<MyGenericClass<T>> MyGenericList = new List<MyGenericClass<T>>(); 

     // I receive the parametric argument T2 here as part of an Expresion. 
     // And I keep the expression in my list. 
     public MyGenericClass<T, T2> ReceivingMethod<T2>(Expression<Func<T, T2>> expression) 
     { 
      MyGenericClass<T, T2> genericImp = new MyGenericClass<T, T2>(expression); 
      MyGenericList.Add(genericImp); 
      return genericImp; 
     } 
    } 

    public class Client<T> 
    { 
     MyClass<T> class1; 

     // class1 has been created and his field MyGenericList has beed populated. 
     // Then when I call Do().... 
     public void Do() 
     { 
      foreach (var item in class1.MyGenericList) 
      { 
       // ...I need something like this here, 
       // but it does not compile because I don't know T2 here. 
       // The caller of Do() method doesn't know T2. 
       MyGenericClass<T, T2> myGenericItem = (MyGenericClass<T, T2>)item; 
       var a = myGenericItem.expression; 
      } 

     } 
    } 
+1

你有沒有考慮過使用代替? –

+1

此時您必須使用反射。或者真的試圖找出不同的設計。泛型旨在讓您編寫大多數與類型無關的代碼,而不是讓您將許多不同類型組合在一起。 – juharr

+1

'Do'會如何使用'myGenericItem'?如果它不需要做特定於'T2'的任何事情,那麼你可以在派生類中實現的'MyGenericClass '上定義抽象方法,並由'Do'調用。 – KMoussa

回答

0

解決方案1 ​​從@KMoussa評論啓發。我已經使用抽象方法將可責任性委託給MyGenericClass。這似乎是一個更好的設計。所有的子類都會實現這個方法(DoTheWork())。並且可以從我的Client.Do()方法被調用只有牛逼PARAM:

public abstract class MyGenericClass<T> 
    { 
     public abstract string DoTheWork(); 
    } 

    public class MyGenericClass<T, T2> : MyGenericClass<T> 
    { 
     public override string DoTheWork() 
     { 
      // .... I can use expression here 
     } 

     private Expression<Func<T, T2>> expression { get; set; } 

     public MyGenericClass(Expression<Func<T, T2>> expression) 
     { 
      this.expression = expression; 
     } 
    } 

    public class MyClass<T> 
    { 
     public List<MyGenericClass<T>> MyGenericList = new List<MyGenericClass<T>>(); 
     public void ReceivingMethod<T2>(Expression<Func<T, T2>> expression) 
     { 
      MyGenericClass<T, T2> genericImp = new MyGenericClass<T, T2>(expression); 
     } 
    } 

    public class Client<T> 
    { 
     MyClass<T> class1; 
     public void Do() 
     { 
      // I don't need to cast to MyGenericClass<T, T2> 
      foreach (MyGenericClass<T> myGenericItem in class1.MyGenericList) 
      { 
       string result = myGenericItem.DoTheWork(); 
      } 

     } 
    } 

解決方案從@ ja72和@juharr意見的啓發2。使用反射。首先,我使用抽象屬性在MyGenericClass上保存類型T2。然後我可以調用使用反射,所以我可以介紹一下參數鑄造的一般方法(MethodWithArgument):

public abstract class MyGenericClass<T> 
{ 
    public abstract Type type { get; set; } 
} 

public class MyGenericClass<T, T2> : MyGenericClass<T> 
{ 
    public Expression<Func<T, T2>> expression { get; set; } 

    public MyGenericClass(Expression<Func<T, T2>> expression) 
    { 
     type = typeof(T2); // I save the type of T2 
     this.expression = expression; 
    } 
} 

public class MyClass<T> 
{ 
    public List<MyGenericClass<T>> MyGenericList = new List<MyGenericClass<T>>(); 
    public void ReceivingMethod<T2>(Expression<Func<T, T2>> expression) 
    { 
     MyGenericClass<T, T2> genericImp = new MyGenericClass<T, T2>(expression); 
    } 
} 

public class Client<T> 
{ 
    MyClass<T> class1; 
    public void Do() 
    { 
     foreach (MyGenericClass<T> myGenericItem in class1.MyGenericList) 
     { 
      MethodInfo method = GetType().GetMethod("MethodWithArgument"); 
      MethodInfo generic = method.MakeGenericMethod(new Type[] { myGenericItem.type }); 
      string g = (string)generic.Invoke(this, new object[] { myGenericItem }); 
     } 
    } 

    // I introduce T2 in this method 
    public string MethodWithArgument<T2>(MyGenericClass<T> myClass) 
    { 
     // Now, the casting is valid 
     MyGenericClass<T, T2> mySubClass = (MyGenericClass<T, T2>)myClass; 
     var a = mySubClass.expression; 
     // ... I can work with expression here 
    } 
} 
1

你必須給Do()T2參數莫名其妙。所以我的解決方案是創建一個相同類型的方法參數。我也嵌套了各種類型,以確保它們都指向相同的T

我也改名爲參數,以更具描述

// T -> TArg 
// T2 -> TResult 
public abstract class MyBaseClass<TArg> 
{ 
    public class MyExpressionClass<TResult> : MyBaseClass<TArg> 
    { 
     public Expression<Func<TArg, TResult>> Expression { get; private set; } 
     public MyExpressionClass(Expression<Func<TArg, TResult>> expression) 
     { 
      this.Expression=expression; 
     } 
    } 

    public class MyCollectionClass 
    { 
     public List<MyBaseClass<TArg>> MyGenericList = new List<MyBaseClass<TArg>>(); 

     public MyExpressionClass<TResult> ReceivingMethod<TResult>(Expression<Func<TArg, TResult>> expression) 
     { 
      var genericImp = new MyExpressionClass<TResult>(expression); 
      MyGenericList.Add(genericImp); 
      return genericImp; 
     } 
    } 

    public class Client 
    { 
     public MyCollectionClass List = new MyCollectionClass(); 

     public void Do<TResult>() 
     { 
      foreach(var item in List.MyGenericList) 
      { 
       var expr = item as MyExpressionClass<TResult>; 
       if(expr!=null) 
       { 
        var a = expr.Expression; 
        Console.WriteLine(a); 
       } 
      } 
     } 
    } 
} 



class Program 
{ 
    static void Main(string[] args) 
    { 
     var client = new MyBaseClass<int>.Client(); 
     // add conversion expressions 
     client.List.ReceivingMethod((i) => (i).ToString()); 
     client.List.ReceivingMethod((i) => (2*i).ToString()); 
     client.List.ReceivingMethod((i) => (3*i).ToString()); 

     // The programmer has to manually enforce the `string` type 
     // below based on the results of the expressions above. There 
     // is no way to enforce consistency because `TResult` can be 
     // _any_ type. 
     client.Do<string>(); 

     // Produces the following output 
     // 
     // i => i.ToString() 
     // i => (2*i).ToString() 
     // i => (3*i).ToString() 
    } 
} 
+0

我無法編譯'MyExpressionClass ...'。我需要添加類型參數'TArg':'MyExpressionClass ... ...'進行編譯。問題在於'Do()'的調用者不知道'' – Jesus

+0

我的例子中的代碼編譯了100%。我發佈之前檢查過它。如果出現錯誤,可能是某處存在拼寫錯誤。 'MyExpression <>'嵌套_inside_'MyBaseClass <>',它使用'TArg'。 – ja72

+0

是的,編譯100%。我不會看到階級嵌套。抱歉!! – Jesus

相關問題