vendredi 23 mars 2018

C# set CollectionChanged via lambda expression and reflection

(apologies if this turns out to be duplicate, but i couldn't get it - maybe didn't know what to search for, so i appreciate if you point me to the right direction)

I want to initialize an ObservableCollection and set the CollectionChanged event handler using lambda expression and reflection. So, having:

public Collection<string> MyCollection { get; private set; }

private void DoSomething<T>(string collectionName, NotifyCollectionChangedEventArgs e) 
{ //do something with the PropertyInfo having collectionName }

I want to be able to reproduce...:

MyCollection = new ObservableCollection<string>();
MyCollection.CollectionChanged += (s,e) => { DoSomething<string>("MyCollection", e); }

...using something like this:

(notice that the call to DoSomething doesn't use the s argument, but the property name instead - which i want to retrieve from a PropertyInfo - this is a must)

void InitializeGenericCollection(PropertyInfo property)
{  
   //create my ObservableCollection<T> instance
   Type[] types = property.PropertyType.GetGenericArguments();
   var ocType = typeof(ObservableCollection<>).MakeGenericType(types[0]);
   var collection = Activator.CreateInstance(ocType);

   // get CollectionChanged and DoSomething
   EventInfo eventInfo = ocType.GetEvent("CollectionChanged");
   MethodInfo method = (typeof(A)).GetMethod("DoSomething", BindingFlags.NonPublic | BindingFlags.Instance).MakeGenericMethod(types[0]);

   // create a handler with expression 
   // (s, e) => { method.Invoke(this, new object[] { property.Name, e }); };

   var sParam = Expression.Parameter(typeof(object), "s");
   var eParam = Expression.Parameter(typeof(NotifyCollectionChangedEventArgs), "e");      

   // !! THIS IS WHERE I AM STUCK !!
   MethodCallExpression lambda = Expression.Call(method, new ParameterExpression[] {????, eParam});     

   Delegate handler = Delegate.CreateDelegate(eventInfo.EventHandlerType, collection, lambda.Method);
   eventInfo.AddEventHandler(collection, handler);
   p.SetValue(this, collection);
}

Notice the "THIS IS WHERE I AM STUCK" line:

  • how do I create and pass the ??? parameter which is the property.Name ? (i'm confused, since it is not a constant, but it is known at compile time)
  • I guess i need to create the sParam for the handler to match the signature of the event handler, but i don't plan on using it - so (this may sound silly) how do I ignore it, but still get a valid handler?

My hunch is that i need to create a larger expression tree, but how?

Thanks in advance.





Aucun commentaire:

Enregistrer un commentaire