我可以使用字符串方法名称在c#dynamic上调用方法吗?

时间:2013-04-18 18:41:43

标签: c# dynamic signalr

我想知道是否可以通过字符串在动态c#对象上调用函数。我想做这样的事情:

string lMethodName = "MethodName";
dynamic lDynamicObject = GetDynamicObject();
lDynamicObject.Invoke(lMethodName, lParameters);

非常感谢任何想法或解决方案。

也许像Servy说的那样,通过不同的设计实现我们想要的更好的方式。我们正在使用SignalR并拥有仪表板Web应用程序。我们希望仪表板内的每个小部件都能够将数据推送到它。为了实现这一点,我们将使用剃刀代码将widget ID注入到每个单独的小部件SignalR客户端代理中。每个小部件都具有以下内容:

hub.client.updateWidget123456 = aUpdateFunction;

其中123456是小部件的ID。在服务器端SignalR集线器代码上,我们可以回调客户端javascript函数:

int lWidgetId = 123456;
dynamic lDynamic = Clients.All;
lDynamic.Invoke("updateWidget" + lWidgetId, lParameters);

我可以考虑在不创建javascript代理方法的情况下实现此方法。我认为这很好,因为服务器与每个小部件都有直接的通信线路。哪些可以从多个仪表板/浏览器访问,但它们都可以通过上面的单个调用进行更新。

我们可以通过调用javascript客户端代码中的其他对象来实现这一点,该代码知道所有小部件以及如何将信息定向到它们。我觉得这违背了SignalR的集线器架构,就像我们通过这样做重新发明轮子一样。

有没有人对更好的设计方法有任何想法?感谢您的帮助和感谢您的评论Servy引发了这场讨论。

此外,这个问题不重复。另一个问题与保罗在下面评论的动态对象无关。

4 个答案:

答案 0 :(得分:2)

如果您知道它是普通的C#对象(即没有特殊的运行时绑定程序),则只能使用反射来调用dynamic上的方法。

考虑以下实现可动态使用的属性包的类:

public class PropertyBag : DynamicObject
{
    private Dictionary<string, object> _propertyBag = new Dictionary<string, object>();

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        return _propertyBag.TryGetValue(binder.Name, out result);
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        _propertyBag[binder.Name] = value;
        return true;
    }

    public override IEnumerable<string> GetDynamicMemberNames()
    {
        return base.GetDynamicMemberNames();
    }
}

完成以下操作是完全有效的:

dynamic propertyBag = new PropertyBag();

propertyBag.Name = "stackoverflow";
propertyBag.Value = 42;

但是,如果您尝试获取任何这些动态属性的PropertyInfo,它将失败,因为PropertyBag类没有实现它们:

public static void SetProperty(dynamic propertyBag, string propertyName, object value)
{
    PropertyInfo property = propertyBag.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
    if (property == null)
    {
        throw new NotImplementedException();
    }

    MethodInfo setProperty = property.GetSetMethod();
    setProperty.Invoke(propertyBag, new object[] { value });
}

这将抛出异常:

dynamic propertyBag = new PropertyBag();

propertyBag.Name = "stackoverflow;      // works as expected
SetProperty(propertyBag, "Value", 42);  // throws a NotImplementedException

我在这个例子中使用了属性,因为它们更容易实现,但显然同样适用于方法。这样做的原因是dynamic在运行时动态评估,但反射只能反映静态实现。 (GetProperties类应该PropertyBag返回哪些属性?)

如果您将dynamic与普通的C#对象一起使用,那么反射将按预期工作,但如果您不知道您正在使用哪种类型的运行时绑定器以及如何在内部实现它,则无法依赖它。

答案 1 :(得分:1)

通过反思,我认为你可以做那样的事情(如果它是私人的 - &gt; NonPublic)

MethodInfo dynMethod = this.GetType().GetMethod("MethodName" + itemType, BindingFlags.NonPublic | BindingFlags.Instance);
dynMethod.Invoke(this, new object[] { methodParams });

只需使用接受BindingFlags的重载版GetMethod:

答案 2 :(得分:1)

简短回答,是的,你可以这样做:

        class MyClass { public void Action() { Console.WriteLine("Do action"); } }
        // ...
        dynamic instance = new MyClass();
        instance.GetType().GetMethod("Action").Invoke(instance, null);

但是在这种情况下,实例是动态类型的事实绝对没有任何意义。您可以使用object类型,它将以相同的方式工作。链中的第一个方法,GetType()返回typeof(MyClass),然后从那里开始它是普通的老式反射。

使用动态关键字可以做到这一点,这更有趣,虽然在运行时稍微不那么灵活:

        dynamic instance = new MyClass();
        instance.Action();

这将使用反射在运行时查找操作。在此示例中,dynamicvar的工作方式不同,因为此处设置了MyClass,但您可以使用第二行执行任何方法命名操作,只要该实例有一个具有该名称的方法。

答案 3 :(得分:0)

是的,这是可能的。您想要做的是“反射”,并且可以使用大多数更高级别的语言

以下是reflection in C的示例。它实际上非常强大,允许您使代码“在某种程度上”了解自己“