我可以使用字符串方法名在c#动态上调用一个方法吗

本文关键字:方法 调用 一个 动态 可以使 字符串 我可以 | 更新日期: 2023-09-27 18:09:59

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

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

任何想法或解决方案都将不胜感激。

也许就像Servy说的那样,有一种更好的方法可以通过不同的设计来实现我们想要的。我们正在使用SignalR,并有一个仪表板web应用程序。我们希望仪表板中的每个小部件都能够将数据推送到它。为了实现这一点,我们将使用剃刀代码将小部件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引发此次讨论的评论。

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

我可以使用字符串方法名在c#动态上调用一个方法吗

只有当您知道dynamic是一个普通的C#对象(即没有特殊的运行时绑定器(时,才能使用反射来调用它。

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

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#对象一起使用,反射将按预期工作,但如果您不知道要处理的是什么类型的运行时绑定器以及它是如何在内部实现的,则不能依赖它。

通过反思,我认为你可以做这样的事情(如果是私有的->NonPublic(

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

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

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

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

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

使用dynamic关键字可以做到这一点,这更有趣,尽管在运行时灵活性稍低:

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

这将在运行时使用反射查找操作。在这个例子中,dynamicvar的工作方式不同并不明显,因为这里设置了MyClass,但只要实例有一个同名的方法,就可以使用第二行执行名为action的ANY方法。

是的,这是可能的。你想做的被称为"反射",在大多数高级语言中都可以使用

这里是C中反射的一个例子。它实际上非常强大,可以让你的代码在一定程度上"意识到自己">