在 C# 中使用方法属性调用非静态方法

Call non-static methods with method attributes in C#

我目前有一个工作系统,当静态方法具有事件属性和单个 Event 类型的参数时,它可以被 EventSystem 调用。

示例方法

[EventAtribute]
public static void thisIsAnEventHandler(Event ev)
{
  print(ev.ToStrring());
}

当我调用此函数时,它会获取所有具有此事件类型的方法并调用它,MethodInfo.Invoke 接受 null 对象,因为所有方法都是静态的。

public static void callMethodsWithEvent(Event ev)
        {
            // triggers when initEventSystem has not been called
            Debug.Assert(_eventMethods != null);
            
            var methods = _eventMethods
            .Where(x => x.GetParameters()[0].ParameterType == ev.GetType())
            .Where(x => x.GetParameters().Length == 1)
            .Where(x => x.IsStatic);

            foreach (var method in methods) // iterate through all found methods
            {
                method.Invoke(null, new object[] {ev});
            }
        }

如何在启动时存储所有方法

public static void initEventSystem()
        {
            _eventMethods = AppDomain.CurrentDomain
                .GetAssemblies() // Returns all currenlty loaded assemblies
                .SelectMany(x => x.GetTypes()) // returns all types defined in this assemblies
                .Where(x => x.IsClass) // only yields classes
                .SelectMany(x => x.GetMethods())
                .Where(x => x.GetCustomAttributes(typeof(EventAtribute), false).FirstOrDefault() != null)
                .ToList();
        }

尽管这个系统运行良好,但它只适用于静态方法。我知道我需要将一个对象引用传递给 Invoke 方法,但我希望能够创建事件并让任何具有该事件的方法被调用,而无需考虑它。

所以我认为我需要的是能够获取具有此方法签名的所有对象,并分别调用所有这些对象中的所有这些方法。有没有办法不用遍历堆就可以做到这一点。

谢谢。

根据上面的评论,我建议如下解决方案(只是一个粗略的想法,实施将需要更多细节)。是的,接口只提供方法,不提供实现。但这与委托完全相同,它也只是对如何调用某个方法的定义,而不是实现本身。接口实际上可以看作是连接在一起的委托的集合。

创建一个可以附加到 classes 的属性,告诉您的事件系统这些 classes 可以接收某些事件:

    /// <summary>
    /// Declares the visibility of a component.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
    public sealed class InterfaceSupportAttribute : Attribute
    {
        private Type[] m_supportedInterfaces;

        public InterfaceSupportAttribute()
        {
            m_supportedInterfaces= new Type[0];
        }

        public Type[] SupportedInterfaces
        {
            get => m_external;
            set => m_external = value.Distinct().ToArray();
        }
    }

使用如下:


public interface IMyFunctionality
{
    public void Foo();
}

[InterfaceSupportAttribute(SupportedInterfaces = new[] {typeof(IMyFunctionality)}) 
public class MyClass : IMyFunctionality
{
   public MyClass() {...}
   public void Foo() {...}
}

然后,在代码的其他地方:


MyClass c = new MyClass();
RegisterType(c);

并且 RegisterType 函数提取属性并保留对 class 的引用。然后使用另一个函数查询所有实现 IMyInterface 的 classes。您可以自己实现这些功能,也可以使用现有的 Dependency Injection Framework,例如 NInject。这些提供了注册 classes(及其接口)和查询已注册 classes 的特定接口的功能。

注意:我从未使用过 unity,但我实际上假设它已经包含这样一个依赖注入框架,因为许多较大的软件包以一种或另一种形式使用它。