[英]How to pass method parameter when expected to be generic interface base type in c#?
假设我有一个定义如下的接口:
interface IContract
{
void CommonMethod();
}
然后是另一个继承自此接口的接口,该接口以下列方式定义:
interface IContract<T> : IContract where T : EventArgs
{
event EventHandler<T> CommonEvent;
}
我的具体问题是 ,给定实施IContract
任何实例,我如何确定是否也是IContract<T>
,如果是这样, IContract<T>
的通用类型是什么,没有硬编码每种已知类型的IContract<T>
I可能会遇到。
最后,我会使用此决定来调用以下模式:
void PerformAction<T>(IContract<T> contract) where T : EventArgs
{
...
}
当你需要一个IContract<T>
的实例时,你必须首先使用反射来获取泛型类型参数,然后调用适当的方法:
// results in typeof(EventArgs) or any class deriving from them
Type type = myContract.GetType().GetGenericArguments()[0];
现在获取IContract<T>
的泛型类型定义并获取适当的方法。
// assuming that MyType is the type holding PerformAction
Type t = typeof(MyType).MakeGenericType(type);
var m = t.GetMethod("PerformAction");
另外,如果只有方法PerforAction
是通用的而不是MyType
:
// assuming that MyType is the type holding PerformAction
Type t = typeof(MyType);
var m = t.GetMethod("PerformAction").MakeGenericMethod(type);
现在,您应该可以在IContract
的实例上调用该方法:
var result = m.Invoke(myInstance, new[] { myContract } );
myInstance
的类型为MyType
。
这是我用过的解决方案:
首先,非常感谢@HimBromBeere提供此解决方案的基础。 从本质上讲,他发布的内容就是答案,但这里包含了我如何实现这种架构的相关细节。
给定以下接口:
interface IContract
{
void CommonMethod();
}
interface IContract<T> : IContract where T : EventArgs
{
event EventHandler<T> CommonEvent;
}
我有一个类,所有意图和目的都声明如下:
abstract class BaseControl
{
protected void SubscribeToContract<Type>(IContract<Type> contract)
where Type : EventArgs
{
contract.ContractChanged +=
delegate(object sender, Type e)
{
// Calls this method to perform other actions:
OnContractChanged(e);
};
}
// Called when IContract<>.ContractChanged is raised:
protected virtual void OnContractChanged(EventArgs e);
}
class SpecialControl : BaseControl, IContract<SpecialEventArgs>
{
...
protected override OnContractChanged(EventArgs e)
{
base.OnContractChanged();
PerformAction(e);
}
...
void PerformAction(EventArgs e)
{
// We can also now find out if "e" is SpecialEventArgs
if (e is SpecialEventArgs)
{
...
}
...
}
...
}
其中,方法SubscribeToContract<Type>()
是从BaseControl
继承的受保护成员。 这允许派生类实现自己的方法,如PerformAction()
同时抽象而不必担心处理泛型接口的东西(目标)。
在我的类中有一个event
,我使用以下语句来确定参数是否实现IContract
,它是IContract<>
的基本接口:
if (e.Control is IContract)
{
// Gets all the IContract<> interfaces e.Control implements:
var generics = GetIContractGenerics(e.Control.GetType());
// There might be multiple IContract<> implementations
// so therefore we need to check them all, even though in
// practice there will likely only be a single instance:
foreach (var generic in generics)
{
var method = this.GetType().GetMethod(
"SubscribeToContract", (BindingFlags.Instance | BindingFlags.NonPublic));
method = method.MakeGenericMethod(generic);
var result = method.Invoke(this, new[] { e.Control });
}
}
在我的情况下,需要设置(BindingFlags.Instance | BindingFlags.NonPublic)
才能使GetMethod()
函数返回SubscribeToContract<Type>()
方法。
使用此StackOverflow帖子中描述的方法创建方法GetIContractGenerics()
位置 :
protected static IEnumerable<Type> GetIContractGenerics(Type type)
{
return
from implementation in type.GetInterfaces()
where implementation.IsGenericType
let definition = implementation.GetGenericTypeDefinition()
where definition == typeof(IContract<>)
select implementation.GetGenericArguments().First();
}
为方便起见,此GetIContractGenerics()
静态方法存储在BaseControl
中。
多数民众赞成,一切正常! 谢谢各位的意见!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.