Кастинг в дженериках с использованием отражения - PullRequest
0 голосов
/ 18 октября 2018

У меня есть 3 класса со следующей структурой.И у меня есть универсальный метод, который обновляет коллекцию, чтобы проверить, обновляется ли коллекция каким-либо образом или нет.Этот метод работает хорошо, за исключением случаев, когда в модели, которую вы пытаетесь обновить, есть Observablecollection.

Так что в TestClassA я вызываю мой общий метод Collectionrefresh для TestClassB.Но у 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;}
}

Теперь, чтобы преодолеть эту проблему, я изменил свой метод следующим образом.

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
}

Это не работает, потому что dynamic будет object, и я хочу, чтобы актерский состав был ObservableCollection<TestClassC>.Если я произнесу ObservableCollection<T>, это даст мне неправильную ошибку, потому что T будет TestClassB в то время, и я хочу, чтобы оно было TestClassC.После приведения ObservableCollection<TestClassC> к collection1 и collection2 моя проблема решена, но, поскольку я делаю дженерики, я пытаюсь найти способ сделать это дженериками.

1 Ответ

0 голосов
/ 18 октября 2018

В моем понимании, ваша конечная цель будет void collection1.CollectionRefresh(collection2)

, где collection1.GetType()==collection2.GetType()==typeof(ObservableCollection<TestClassC>)

Полагаю, вы хотите позвонить

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

Тогда Tбудет TestClassB, а ObservableCollection<TestClassC> CollectionB будет вашим целевым свойством.

property.GetValue(TestClassB someB) будет возвращать объект, который не может вызывать void CollectionRefresh(collection2), поэтому вы застряли, я прав??

Это вложенная общая проблема.Если бы вы также указали TestClassC как T2, тогда это было бы так просто.

Обычно у нас был бы неуниверсальный базовый класс, чтобы мы могли явно привести его к этому.К сожалению, ObservableCollection<T> не наследуется от функционального ObservableCollection класса.

Вот мое предложение.Вы должны использовать как дерево выражений, так и отражение, чтобы получить метод CollectionRefresh и затем вызвать его, но это может быть излишним.

В любом случае, попробуйте это.

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
}
...