简体   繁体   English

使用反射强制转换泛型

[英]Casting in generics using reflection

I have 3 classes with the following structure. 我有3个具有以下结构的课程。 And I have a generic method that refreshes the collection to check if the collection is updated in any way or not. 我有一个通用的方法来刷新集合以检查集合是否以任何方式更新。 This method works fine except if it has Observablecollection inside the model you are trying to update. 此方法可以正常工作,除非您要更新的模型中具有Observablecollection。

So in TestClassA , I am calling my generic Collectionrefresh method for TestClassB . 因此,在TestClassA ,我正在为TestClassB调用通用的Collectionrefresh方法。 But TestClassB have a ObservableCollection which is not updating. 但是TestClassB有一个ObservableCollection,它不会更新。

public class TestClassA
{
   public ObservableCollection<TestClassB> CollectionA {get; set;}

   CollectionA.CollectionRefresh(CollectionB)    //Here CollectionB is the updated list
}

public class TestClassB
{
   public ObservableCollection<TestClassC> TestClassB {get; set;}
   public string Name {get; set;}
}

public class TestClassC
{
   public string FirstName {get; set;}
   public string LastName {get; set;}
}

Now to overcome this problem I have modified my method this way. 现在,为了克服这个问题,我已经用这种方式修改了我的方法。

public static void CollectionRefresh<T>(this ObservableCollection<T> collection, List<T> items)
{
   //Method Content

   PropertyInfo[] properties = typeof(T).GetProperties();


   foreach(PropertyInfo property in properties)
   {
      if (property.PropertyType.IsGenericType && typeof(ObservableCollection<>).IsAssignableFrom(property.PropertyType.GetGenericTypeDefinition()))
      {
         //I am getting the oldCollection and newList from somewherelse in the method.
         var collection1 = (dynamic)property.GetValue(oldCollection);
         var collection2 = (dynamic) property.GetValue(newList);

         collection1.CollectionRefresh(collection2);
      }
   }

   //Method Content
}

This is not working because dynamic will be an object and I want the cast it to be ObservableCollection<TestClassC> . 这不起作用,因为dynamic将是一个object并且我希望将其ObservableCollection<TestClassC>转换为ObservableCollection<TestClassC> If I cast ObservableCollection<T> it gives me incorrect cast error because T will be TestClassB at that time and I want it to be TestClassC . 如果我ObservableCollection<T>则会给我错误的强制转换错误,因为那时T将为TestClassB ,而我希望它为TestClassC Upon casting ObservableCollection<TestClassC> to both collection1 and collection2, my problem is solved but since I am doing generics I am trying to find a way to do it generic. 在将ObservableCollection<TestClassC>转换为collection1和collection2时,我的问题已解决,但是由于我正在执行泛型,因此我试图找到一种使它成为泛型的方法。

In my understanding, your ultimate goal would be void collection1.CollectionRefresh(collection2) 以我的理解,您的最终目标将是void collection1.CollectionRefresh(collection2)

where collection1.GetType()==collection2.GetType()==typeof(ObservableCollection<TestClassC>) 其中collection1.GetType()==collection2.GetType()==typeof(ObservableCollection<TestClassC>)

I suppose you want to call 我想你想打电话

TestClassA testA = new TestClassA();
List<TestClassB> list = new List<TestClassB>();
testA.CollectionA.CollectionRefresh(list);

Then T is going to be TestClassB and ObservableCollection<TestClassC> CollectionB is your targeted property. 然后T将成为TestClassBObservableCollection<TestClassC> CollectionB是您的目标属性。

property.GetValue(TestClassB someB) is going to return an object, which is not eligible to call void CollectionRefresh(collection2) so you are now stuck, am I correct? property.GetValue(TestClassB someB)将返回一个对象,该对象不具备调用void CollectionRefresh(collection2)资格,因此您现在被卡住了,对吗?

This is a nested generic problem. 这是一个嵌套的通用问题。 If you also given TestClassC as T2 then it would be so easy. 如果您也将TestClassCT2那将非常容易。

Usually we would have a non-generic base class so that we could explicitly cast to that. 通常,我们将有一个非泛型基类,以便可以将其显式转换为该基类。 Unfortunately, ObservableCollection<T> is not inherited from a functional ObservableCollection class. 不幸的是, ObservableCollection<T>不是从功能性ObservableCollection类继承的。

Here is my suggestion. 这是我的建议。 You have to use both an expression tree and reflection to get the CollectionRefresh method and then call it, but that might be an overkill. 您必须同时使用表达式树和反射来获取CollectionRefresh方法,然后再调用它,但这可能是一个过大的选择。

Anyway, try this. 无论如何,尝试一下。

public static void CollectionRefresh<T>(this ObservableCollection<T> collection, List<T> items)
{
   //Method Content

   PropertyInfo[] properties = typeof(T).GetProperties();


   foreach(PropertyInfo property in properties)
   {
      if (property.PropertyType.IsGenericType && typeof(ObservableCollection<>).IsAssignableFrom(property.PropertyType.GetGenericTypeDefinition()))
      {
        MethodInfo refreshMethod = property.PropertyType.GetMethod("CollectionRefresh");

        var instanceT1 = Expression.Parameter(typeof(T), "otherT1");
        var instanceT2 = Expression.Parameter(typeof(T), "otherT2");
        var prop1 = Expression.Call(instanceT1, property.GetMethod);
        var prop2 = Expression.Call(instanceT2, property.GetMethod);
        var collection1 = Expression.Convert(prop1, property.PropertyType);
        var collection2 = Expression.Convert(prop2, property.PropertyType);
        var refresh = Expression.Call(collection1, refreshMethod, collection2);
        var lambda = Expression.Lambda<Action<T, T>>(refresh, instanceT1, instanceT2);

        Action<T, T> func = lambda.Compile();
        func(oldCollection, newList);
      }
   }

   //Method Content
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM