【问题标题】:Storing object instance method with given attribute to be called later存储具有给定属性的对象实例方法,以便稍后调用
【发布时间】:2020-05-04 10:07:09
【问题描述】:

正如标题所说,使用反射我得到了具有给定属性的类型的方法。然后我想存储该对象实例的该方法,以便以后可以调用它。我不确定如何将该方法与该实例一起存储在包含 Action 的字典中。消息是字典中的关键用途。所有具有此属性的方法都需要采用 1 个动态类型的参数。

static Dictionary<string, Action<dynamic>> networkHooks = new Dictionary<string, Action<dynamic>>();

private static void RegisterNetworkMethods(Type type, INetworkEnabled obj)
{
    // get the methods of this type that have the NetworkMethodAttribute
    var methods = (from m in type.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
                       where m.GetCustomAttributes(false).OfType<NetworkMethodAttribute>().Count() > 0
                       select m).ToList();

    foreach(var method in methods)
    {
        // get the NetworkMethodAttribute Message variable that was assigned
        var message = method.GetCustomAttribute<NetworkMethodAttribute>().Message;

        // todo: store this instance method in an Action somehow so it can be called later
        // networkHooks.Add(message, ???);
    }
}

【问题讨论】:

  • 看起来您正在走上正轨...您只需将MethodInfo method 转换为Action&lt;dynamic&gt; @delegate 并存储它...这里有一个链接可以帮助您。 stackoverflow.com/questions/3021578/…
  • 您是否使用Action&lt;dynamic&gt;,因为该方法可以采用任何类型的参数?

标签: c# reflection


【解决方案1】:

如果您使用Action&lt;dynamic&gt;,因为这些方法可以采用任何类型的参数,您可以使用此版本使其工作。然后,您可以在 Dictionary 中存储的委托上调用 DynamicInvoke(param) 来调用方法

static Dictionary<string, Delegate> networkHooks = new Dictionary<string, Delegate>();

private static void RegisterNetworkMethods(Type type, object target)
{
    // get the methods of this type that have the NetworkMethodAttribute
    var methods = (from m in type.GetMethods(NonPublic | Instance)
                   where m.GetCustomAttributes(false).OfType<NetworkMethodAttribute>().Count() > 0
                   select m).ToList();

    foreach (var method in methods)
    {
        // get the NetworkMethodAttribute Message variable that was assigned
        var message = method.GetCustomAttribute<NetworkMethodAttribute>().Message;

        // todo: store this instance method in an Action somehow so it can be called later
        networkHooks.Add(message, Delegate.CreateDelegate(typeof(Action<Anything>).GetGenericTypeDefinition().MakeGenericType(method.GetParameters()[0].ParameterType), target, method.Name));
    }
}

旁注:.OfType&lt;NetworkMethodAttribute&gt;().Count() &gt; 0 可以改成.OfType&lt;NetworkMethodAttribute&gt;().Any(),这样更快

【讨论】:

  • 这怎么知道要调用的对象实例?
  • 使用对象实例似乎也丢失了。我假设您可能认为我稍后会在其他时间创建这些对象,但我在运行此代码以存储它们的函数委托之前创建了这些对象。
  • @user441521 当你调用RegisterNetworkMethods时你有这些对象的引用吗?
  • 是的,我在调用 RegisterNetworkMethods 时创建和管理所有这些对象实例。这是针对游戏的,因此这些类实例在游戏运行时会做很多其他事情。他们只需要一种方法来知道我们何时从服务器收到消息,以便他们可以使用消息的数据在内部更新他们的状态。
  • @user441521 好的,我正在根据此编辑我的答案,您可以查看我对您的问题所做的编辑吗?
【解决方案2】:

这样的事情应该会让你朝着正确的方向前进。

    private static void RegisterNetworkMethods(Type type, INetworkEnabled obj)
    {
        // get the methods of this type that have the NetworkMethodAttribute
        var methods = (from m in type.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
                       where m.GetCustomAttributes(false).OfType<NetworkMethodAttribute>().Count() > 0
                       select m).ToList();

        foreach(var method in methods)
        {
            // get the NetworkMethodAttribute Message variable that was assigned
            var message = method.GetCustomAttribute<NetworkMethodAttribute>().Message;

            var action = (Action<dynamic>) Delegate.CreateDelegate(typeof(Action<dynamic>), method);

            networkHooks.Add(message, action);
        }
    }

【讨论】:

  • 缺少将 obj 传递给 CreateDelegate()。我是从您在评论中发布的链接中得到的。
  • 您必须将对象实例传递给静态方法。请理解,当您在类实例上引用非静态委托时,您将实例引用保留为长期存在的对象......这意味着在不再使用委托并从集合中删除之前,您的实例引用将仍然存在于堆中......我实际上想要传达的是,如果你要使用类实例引用,请确保你自己清理干净。
  • 是的,当然。我为此管理所有对象实例。在这方面不用担心。这是针对游戏的,所讨论的对象实例也在为游戏做很多其他事情,他们只需要知道来自服务器的某些网络消息何时进入,以使用服务器发送的数据更新其内部状态。我将所有这些都集中在一个文件中,但它变得难以管理并且只会增长。所以我想改用这种注册方式,这样每个类实例都可以得到服务器消息和数据的通知并进行自我管理。
猜你喜欢
  • 1970-01-01
  • 2021-09-24
  • 1970-01-01
  • 2012-08-24
  • 1970-01-01
  • 1970-01-01
  • 2023-01-07
  • 2015-08-10
  • 1970-01-01
相关资源
最近更新 更多