1

I am importing methods with MEF. I call this method to get all exported methods:

var methods = container.GetExports<Func<int,int,double>,MyMetadata>("contract name");

NOTE: Sometimes Func<int,int,double> changes. For example it might have more parameters: Func<int,int,int,double>.

When I fire methods I know how many parameters to pass. My question is how can I dynamically pass parameters to imported methods?

UPDATE:

    IEnumerable<Lazy<Func<int,int,double>,MyMetadata>> Plugins; 
    public IEnumerable RunAllPlugins(int a, int b)
    {
        //my old approach
        foreach (var p in Plugins)
        {
            dynamic a = p;
            var b = a.Value.Invoke(a,b); //here I want to pass parameters dynamically
        }
        //this is new approach which is answer
        //now I can pass parameters like array of objects
        foreach(var lazyMethod in Plugins)
        {
            Delegate d=lazyMethod.Value;
            object[] numbers=new object[]{1,2};
            var result=d.DynamicInvoke(numbers);
        }
        return null;
    }
wpf_starter
  • 67
  • 3
  • 11
  • 1
    The bigger question is, if the parameters can change from time to time how will you know what to pass in..! – Sean Apr 22 '13 at 14:25
  • @Sean I specified that I know haw many parameters to pass, but don't know how to pass. Imagine that parameters are integers all the time. – wpf_starter Apr 22 '13 at 14:31
  • Sure, but in your example you'd baked in the type of Func<> you want (int,int,double). How would you get back a method that took a different number of parameters without changing the code? – Sean Apr 22 '13 at 14:37
  • I've expanded my answer below. – Sean Apr 22 '13 at 14:41
  • 1
    I don't thing you're being very clear, and it's causing people to post answes that you keep saying aren't what you're looking for. Why don't you post the code you've got along with an indication of where in it you're stuck. – Sean Apr 22 '13 at 15:23
  • You can't reach this abstraction depth, type parameters must be inferrable at compile-time. Unless I misunderstood the issue, in which case I also suggest you post some more code. – Alex Apr 22 '13 at 15:28

4 Answers4

2

Once you've got the Func<> get its type:

  Type type=someFunction.GetType();

Now get the Invoke member:

  var methodInfo=type.GetMember("Invoke");

This is the method that is actually called when you execute the delegate. You can call GetParameters on the methodInfo to find out how many parameters it takes.

If you already know how many parameters to add, and their type, then things are easier. You just assign to a delegate and call DynamicInvoke:

    Delegate d=someFuncInstance;
    object[] numbers=new object[]{1,2};
    var result=d.DynamicInvoke(numbers);

result will be an object instance which you'll need to cast. someFuncInstance is an instane of Func<> that you've gotten hold of from somewhere.

So, for you MEF example it'd be something like this:

var methods=container.GetExports<Func<int,int,double>,MyMetadata>("contract name");
foreach(var lazyMethod in methods)
{
  Delegate d=lazyMethod.Value;
  object[] numbers=new object[]{1,2};
  var result=d.DynamicInvoke(numbers);
}
Sean
  • 60,939
  • 11
  • 97
  • 136
  • what is someFunctInstance? Could you please explain? – wpf_starter Apr 22 '13 at 15:00
  • I am getting this error: Cannot implicitly convert type 'IEnumerable,MEFPluginTest.Test>>' to 'System.Delegate'. An explicit conversion exists (are you missing a cast?) – wpf_starter Apr 22 '13 at 15:22
  • I've updates the example as best I can (I've never used MEF). You may need to change it slightly. The key point if that you assign your `Func<>` delegate to `d`. – Sean Apr 22 '13 at 15:33
  • I am happy with your answer, but I couldn't assign Func<> to Delegate. – wpf_starter Apr 22 '13 at 15:42
  • You don't assing `Func<>` you assign some `Func<>` instance, eg `Func` or `Func` – Sean Apr 22 '13 at 15:50
1

the type of methods should be IEnumerable<Lazy<Func<int,int,double>> so a simple

 foreach(var method in methods)
 {
      method.Value(a,b);
 }

should work. Or if you want to save it for later:

Func<int,int,double> mySavedDelegate = methods.First();

//...

mySavedDelegate(a,b);

Edit: also its a better practice to export interfaces and execute the required methods off of of the imported interface rather than to export methods directly. I've never done the latter, but assume from your question that its possible in the first place.

Yaur
  • 7,333
  • 1
  • 25
  • 36
  • Thanks for the response, but what do I do when one or more parameter added? – wpf_starter Apr 22 '13 at 15:03
  • @wpf_starter the call to `GetExports` is going to be different. Since the "contract" is different they won't and shouldn't be imported into the same collection. – Yaur Apr 22 '13 at 15:07
  • When I call GetExports I don't just say>. It is generic. it something like this: GetExports. – wpf_starter Apr 22 '13 at 15:10
  • a) It really sounds like you aren't using MEF correctly (import interfaces) b) I don't think you are going to get this to work without either exposing the delegate/collection to code that knows what `TType` is or using reflection (see Sean's answer). – Yaur Apr 22 '13 at 15:38
1

variadic functions should work here.

double Magic(params int[] args)
{
   switch(args.Count)
   {
     case 2: return args[0]+args[1];
     case 3: return args[0]+args[1]/args[3];
     default: throw new Exception("Not supported");
   }
}

and then just call Magic(1, 2); or Magic(1,2,3);

Erti-Chris Eelmaa
  • 25,338
  • 6
  • 61
  • 78
0

I guess you overloading the Func<> interface...

As I understand what you want to get is a list of methods that has a specific signature: it must be method that return double and receive 2 integers ? So may be you should return (!) a List<> as return (!) value ?

Second: it's not possible to fit all methods inside specific Func<> or Action<> or else. Naturally some functions will list different parameters for input and different return values. Right ? So if (!) you want to work only on functions that return double and receive 2 integers so the List<> will be returned only (!) for those types of methods. Please read more on function signature

Third: I guess it's a wrong use of MEF. Basically what MEF is saying is: Define interface in your app, use it as if it was created with new and I (MEF) will plug it in at runtime. So actually you don't need to get a list of any methods. Just make sure that both sides support/define/inherit those methods and use them as if they was defined in your app

Alex F
  • 3,180
  • 2
  • 28
  • 40
  • On my Plugin dll I have 1000 s of methods with different signatures. When I call GetExports> I need only methods with "mysignature" not all methods. And what is wrong with using MEF? – wpf_starter Apr 22 '13 at 15:13
  • It seems that you using MEF for loading dll's only but it not the purpose of MEF. The `GetExports` function *already* exist in MEF core - you don't have to worry about it. *If* you want to do the exports manually do `Reflection` but MEF was build for different purpose – Alex F Apr 23 '13 at 06:23