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

相关问题