[英]How to pass method parameter when expected to be generic interface base type in c#?
Suppose I have an interface defined as follows: 假设我有一个定义如下的接口:
interface IContract
{
void CommonMethod();
}
and then another interface which inherits from this interface defined in the manner of: 然后是另一个继承自此接口的接口,该接口以下列方式定义:
interface IContract<T> : IContract where T : EventArgs
{
event EventHandler<T> CommonEvent;
}
My specific question is , given any instance implementing IContract
, how could I determine if is also IContract<T>
, and if so, what the generic type of IContract<T>
is without hard-coding each known type of IContract<T>
I might encounter. 我的具体问题是 ,给定实施
IContract
任何实例,我如何确定是否也是IContract<T>
,如果是这样, IContract<T>
的通用类型是什么,没有硬编码每种已知类型的IContract<T>
I可能会遇到。
Ultimately, I would use this determination in order to make a call of the following pattern: 最后,我会使用此决定来调用以下模式:
void PerformAction<T>(IContract<T> contract) where T : EventArgs
{
...
}
As you need an instance of IContract<T>
you have to use reflection to get the generic type-param first and than call the appropriate method: 当你需要一个
IContract<T>
的实例时,你必须首先使用反射来获取泛型类型参数,然后调用适当的方法:
// results in typeof(EventArgs) or any class deriving from them
Type type = myContract.GetType().GetGenericArguments()[0];
Now get the generic type-definiton for IContract<T>
and get the appropriate method. 现在获取
IContract<T>
的泛型类型定义并获取适当的方法。
// assuming that MyType is the type holding PerformAction
Type t = typeof(MyType).MakeGenericType(type);
var m = t.GetMethod("PerformAction");
Alternativly if only the method PerforAction
is generic instead of MyType
: 另外,如果只有方法
PerforAction
是通用的而不是MyType
:
// assuming that MyType is the type holding PerformAction
Type t = typeof(MyType);
var m = t.GetMethod("PerformAction").MakeGenericMethod(type);
Now you should be able to invoke the method on an instannce of IContract
: 现在,您应该可以在
IContract
的实例上调用该方法:
var result = m.Invoke(myInstance, new[] { myContract } );
Where myInstance
is of type MyType
. myInstance
的类型为MyType
。
This is the solution I have used: 这是我用过的解决方案:
First off, many thanks to @HimBromBeere for providing the basis of this solution. 首先,非常感谢@HimBromBeere提供此解决方案的基础。 In essence, what he has posted is the answer, however included here are the pertinent details of how I implemented this architecture.
从本质上讲,他发布的内容就是答案,但这里包含了我如何实现这种架构的相关细节。
Given the following interfaces: 给定以下接口:
interface IContract
{
void CommonMethod();
}
interface IContract<T> : IContract where T : EventArgs
{
event EventHandler<T> CommonEvent;
}
I have a classes, which for all intents and purposes are declared as follows: 我有一个类,所有意图和目的都声明如下:
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)
{
...
}
...
}
...
}
Where the method SubscribeToContract<Type>()
is a protected member inherited from BaseControl
. 其中,方法
SubscribeToContract<Type>()
是从BaseControl
继承的受保护成员。 This allows derived classes to implement their own methods like PerformAction()
while abstracting away having to worry about dealing with the generic interface stuff (goal). 这允许派生类实现自己的方法,如
PerformAction()
同时抽象而不必担心处理泛型接口的东西(目标)。
Within my class there is an event
which I use the following statement to determine if the argument implements IContract
, which is the base interface for IContract<>
: 在我的类中有一个
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 });
}
}
In my case setting (BindingFlags.Instance | BindingFlags.NonPublic)
was required in order to get the GetMethod()
function to return the SubscribeToContract<Type>()
method. 在我的情况下,需要设置
(BindingFlags.Instance | BindingFlags.NonPublic)
才能使GetMethod()
函数返回SubscribeToContract<Type>()
方法。
Where the method GetIContractGenerics()
was created using the method described in this StackOverflow post : 使用此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();
}
This GetIContractGenerics()
static method is stored in BaseControl
for convenience. 为方便起见,此
GetIContractGenerics()
静态方法存储在BaseControl
中。
Thats it, everything works! 多数民众赞成,一切正常! Thanks everyone for your input!
谢谢各位的意见!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.