Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# dynamic executing function by its name?

I have a dynamic variable

dynamic d = GetSomeObject();

Sometime , in future, a user send me a function to execute ( its name) e.g "UsersGetAll"

So I need to do something like : d.UsersGetAll()

I can do it with reflection. But I want to use the DLR .

Does the only solution of doing this is to have MyObject inherit from DynamicObject and then implement TryInvokeMember?

What if I don't have control over the class ?

like image 273
Royi Namir Avatar asked Dec 11 '25 01:12

Royi Namir


1 Answers

As Jon notes, the following really only applies if you suspect that the type is providing the method at runtime via the DLR; in most simple cases, reflection will be easier.

dynamic is intended when you know the method name but not the target. If you don't know the method name it is tricker. The tricky bit, perhaps, is ensuring you keep the call-site so that it can be re-used (which is how the DLR maintains performance). One cheeky way would be a static utility class that keeps track of invoked methods. Here's an example - note that it gets much messier if you need to handle parameters:

using Microsoft.CSharp.RuntimeBinder;
using System;
using System.Collections;
using System.Runtime.CompilerServices;
public class Foo
{
    public object Bar() { return "I was here"; }
}
static class Program
{
    static void Main()
    {
        object obj = new Foo();
        object result = DynamicCallWrapper.Invoke(obj, "Bar");
        Console.WriteLine(result);
    }
}

static class DynamicCallWrapper
{
    // Hashtable has nice threading semantics
    private static readonly Hashtable cache = new Hashtable();
    public static object Invoke(object target, string methodName)
    {
        object found = cache[methodName];
        if (found == null)
        {
            lock (cache)
            {
                found = cache[methodName];
                if(found == null)
                {
                    cache[methodName] = found = CreateCallSite(methodName);
                }
            }
        }
        var callsite = (CallSite<Func<CallSite, object,object>>)found;
        return callsite.Target(callsite, target);
    }
    static object CreateCallSite(string methodName)
    {
        return CallSite<Func<CallSite, object, object>>.Create(
            Binder.InvokeMember(
            CSharpBinderFlags.None, methodName, null, typeof(object),
            new CSharpArgumentInfo[] {
                CSharpArgumentInfo.Create(
                     CSharpArgumentInfoFlags.None, null) }));

    }
}
like image 126
Marc Gravell Avatar answered Dec 12 '25 15:12

Marc Gravell



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!