在 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,但我实际上假设它已经包含这样一个依赖注入框架,因为许多较大的软件包以一种或另一种形式使用它。
我目前有一个工作系统,当静态方法具有事件属性和单个 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,但我实际上假设它已经包含这样一个依赖注入框架,因为许多较大的软件包以一种或另一种形式使用它。