2017-04-13 11 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

'' MyGenericItem'をどのように使用するのですか? 'T2'に固有のことをする必要がなければ、' MyGenericClass 'に派生クラスで実装され、' Do'によって呼び出される抽象メソッドを定義することができます – KMoussa

答えて

0

ソリューション1より記述するパラメータの名前を変更しました。私は抽象メソッドを使用してMyGenericClassへの責任を委譲しました。これはより良いデザインのようです。すべてのサブクラスでこのメソッド(DoTheWork())が実装されます。そして、唯一のTのparamで私のClient.Do()メソッドから呼び出すことができます:2は@ ja72と@juharrコメントからインスピレーションを受け

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

     } 
    } 

ソリューション。反射を使用します。まず、抽象プロパティを使用して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

私はまた@KMoussaコメントからインスピレーションを受け

// 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

関連する問題