简体   繁体   English

如何在c#中预期为通用接口基类型时传递方法参数?

[英]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.

相关问题 如何将接口作为参数传递给方法 C# - How to pass a interface as a parameter to a method C# C#:转换为具有基类型的泛型接口 - C#: cast to generic interface with base type 如何在C#中使用参数和返回值通用实现接口方法 - How to implement a method, into interface, with parameter and returned value generic in C# C#-当泛型方法类型为接口时返回实现 - C# - Returning an implementation when generic method type is an Interface 我可以将基本 class 类型作为通用参数传递给接口吗 - Can I pass a base class type as a generic parameter to an interface 如何将className传递给在C#中将泛型作为参数的方法 - How to pass className to a method which gets generic type as a parameter in C# C# 如何将泛型可枚举类型参数传递给另一个需要 IEnumerable 的方法? - C# How to pass generic enumerable type parameter to another method expecting an IEnumerable? C#基类/接口,具有将派生类作为参数接受的通用方法 - C# base class/Interface with a generic method that accepts the derived class as a parameter 如何在C#中实现在接口上返回特定类型的通用方法 - How to implement a generic method that returns a specific type on an interface in C# 具有接口类型约束的C#泛型方法 - C# generic method with interface type constraint
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM