0

Let's say I have a simple class like so:

public class SimpleClass
{
    public List<SomeOtherClass> ListOfStuff { get; } = new List<SomeOtherClass>();
}

SimpleClass itself is unimportant, let's say I've interrogated the type and determined it's of interest for some reason, so all I have is the System.Type object. Now say that I want to access any non static properties/fields on the class that implement ICollection<T> (i.e. ListOfStuff on SimpleClass). I can access/create instances of SimpleClass and I can also dynamically create instances of whatever the collection is made of, but how do I dynamically (and as efficiently as possible) clear or add items to ListOfStuff?

Basically I want to be able to create delegates that I can call later that I can pass an instance of the interested type to, and the method will clear a specific property/field on that instance. Similarly I want another delegate to which I can also pass a instance of the collection's item to (e.g. SomeOtherClass in the above example), and it will add it to the collection on the property.

I have the System.Type of the class I'm interested in, I have the PropertyInfo/FieldInfo of the field(s) I'm interested in, and I can create instances of the class and the item used in the collection.

e.g. (this is not real code!)

Type type = typeof(SimpleClass);
...
// CreateNew is a method that somehow returns a new instance of a type
object test = CreateNew(type);

// GetCollections somehow returns properties/fields that implement ICollection<>
foreach(var collection in GetCollections(type))
{
    // CreateNewCollectionItem somehow returns a new instance of the item used in the collection
    object newItem = CreateNewCollectionItem(collection);

    // how do I implement these two lines?
    var clear = Delegate.CreateDelegate(...);
    var add = Delegate.CreateDelegate(...);
    ...
    clear(test);
    add(test, newItem);
}

How can I make these delegates?

UPDATE: Perhaps I should have said "What's the best/most efficient way to produce these delegates " instead of simply "how". I'm sure I can write some code to do what is necessary, but is there some magic I can use to improve my code? Expressions perhaps?

UPDATE 2: I'm creating my instance of the type using Expressions and was considering using a DynamicMethod or even TypeBuilder to create my delegates, as I'm not up to speed on Expressions. Does anyone have any guidance/helper classes for these as the code to produce them is not exactly readable...?

MadSkunk
  • 3,309
  • 2
  • 32
  • 49
  • For `CreateNew` you may find https://vagifabilov.wordpress.com/2010/04/02/dont-use-activator-createinstance-or-constructorinfo-invoke-use-compiled-lambda-expressions/ of interest. – mjwills Aug 25 '17 at 22:51
  • I already have most of the code I need (including `CreateNew`), but thanks! – MadSkunk Aug 25 '17 at 22:52
  • Use https://msdn.microsoft.com/en-us/library/system.reflection.methodinfo.makegenericmethod(v=vs.110).aspx to invoke a generic method with types known only at runtime. What about making `SimpleClass`? – Dennis Kuypers Aug 25 '17 at 22:53
  • If you do things dynamically, you don't have type safety anyway. So why use generic collections? I don't know if it suits your needs, but why not use the non-generic `ArrayList` instead? – Olivier Jacot-Descombes Aug 25 '17 at 23:20
  • The classes I'm reflecting on are not mine, but will definitely be generic. – MadSkunk Aug 26 '17 at 00:12

1 Answers1

1

Use typeof(ICollection<>).MakeGenericType() to get the interface to ICollection<T>, and then reflection to invoke it:

var addMethod = typeof(ICollection<>).MakeGenericType(type).GetMethod("Add");
var clearMethod = typeof(ICollection<>).MakeGenericType(type).GetMethod("Clear");

clearMethod.Invoke(collection, new object[0]);
addMethod.Invoke(collection, new object[] { test });
Tim
  • 5,940
  • 1
  • 12
  • 18
  • Thanks, I'll add something like this to my tests, I was hoping for something super efficient, but this may be best way. – MadSkunk Aug 26 '17 at 00:16