如何使用C#检查类是否实现并与泛型接口?

时间:2018-10-19 08:09:50

标签: c#

我具有以下界面

public interface IHandleSuccess<T> where T : Event
{
    void Finished(T _event, Listener<T> listener);
}

以及以下课程

public abstract class Listener<T> where T : Event
{
    public abstract void Handle(T _event);
}

下面的类扩展了Listener<T>并且实现了IHandleSuccess<T>

public class SendConfirmationEmail : Listener<UserWasUpdated>, IHandleSuccess<UserWasUpdated>
{
    public override void Handle(UserWasUpdated _event)
    {
        // ...
    }

    public void Finished(UserWasUpdated _event, Listener<UserWasUpdated> listener)
    {
        // ...
    }
}

最后,另一个侦听器扩展了Listener<T>但未实现IHandleSuccess<T>

public class ScheduleOriantation: Listener<UserWasUpdated>
{
    public override void Handle(UserWasUpdated _event)
    {
        // ...
    }
}

应用启动时,我的SendConfirmationEmail获取类已注册到我的IoC容器中。

我想检查已解决的实例是否实现了合同。如果可以,我想调用Finished方法。

public void Announce<T>(T _event) where T : Event
{
    IEnumerable<Listener<T>> listeners = Container.ResolveAll<Listener<T>>()

    foreach (var listener in listeners)
    {
        try
        {
            listener.Handle(_event);

            if (listener is IHandleSuccess<> _listener)
            {
                _listener.Finished(_event, listener);
            }
        }
        catch (Exception e)
        {
            // ...
        }
    }
}

但是,IHandleSuccess<>行给我一个错误

  

意外使用了未绑定的通用名称

由于通用参数将始终扩展Event类,因此我也尝试将代码更改为以下内容

listener.Handle(_event);

if (listener is IHandleSuccess<Event> _listener)
{
    _listener.Finished(_event, listener);
}

但是_listener.Finished(_event, listener)给我以下错误

  

第二个参数不能从Listener<T>转换为Listener<Event>

如何正确纠正此错误?

3 个答案:

答案 0 :(得分:5)

您已经知道IHandleSuccess<>的通用类型,它将是T,因为您声明将从请求中接收Listener<T>

public void Announce<T>(T _event) where T : Event
{
    IEnumerable<Listener<T>> listeners = Container.ResolveAll<Listener<T>>()

    foreach (var listener in listeners)
    {
        try
        {
            listener.Handle(_event);

            if (listener is IHandleSuccess<T> _listener)
            {
                _listener.Finished(_event, listener);
            }
        }
        catch (Exception e)
        {
            // ...
        }
    }
}

以下是“公告”不是通用的示例

public void Announce(Foo _event)
{
    IEnumerable<Listener<Foo>> listeners = Container.ResolveAll<Listener<Foo>>()

    foreach (var listener in listeners)
    {
        try
        {
            listener.Handle(_event);

            if (listener is IHandleSuccess<Foo> _listener)
            {
                _listener.Finished(_event, listener);
            }
        }
        catch (Exception e)
        {
            // ...
        }
    }
}

答案 1 :(得分:5)

这段代码不起作用

var cls = new SendConfirmationEmail();

if (cls is IHandleSuccess<Event> _cls)
{
    _cls.Finished(_event, cls);
}

因为cls的类型为SendConfirmationEmail(),它实现了Listener<UserWasUpdated>,而_cls被强制转换为IHandleSuccess<Event>。 函数_cls.Finished()期望类型为listener而不是Listener<Event>

的参数Listener<UserWasUpdated>

函数Finished(UserWasUpdated _event, Listener<UserWasUpdated> listener)的用途是什么? 查看使用它的方式,可以删除参数c listener并使用this引用当前的侦听器:

所以界面看起来像这样:

public interface IHandleSuccess<T> where T : Event
{
    void Finished(T _event);
}

实施方式如下:

public class SendConfirmationEmail : Listener<UserWasUpdated>, IHandleSuccess<UserWasUpdated>
{
    public override void Handle(UserWasUpdated _event)
    {
        // ...
    }

    public void Finished(UserWasUpdated _event)
    {
        // Call whatever function on your object
        this.Cleanup()
    }
}

要回答您的第一个问题,这是行不通的,因为对泛型的每次使用都是不同的类型:

var cls = new SendConfirmationEmail();

if (cls is IHandleSuccess<> _cls)
{
    // _event and cls types can't be resolved at compilation time here:
    _cls.Finished(_event, cls);
}

如果您希望能够执行此操作,则需要使您的接口非通用。 如果您的对象_event事先知道cls对象,则可以存储它并在Finished()调用中使用它,如下所示:

接口:

public interface IHandleSuccess
{
    void Finished();
}

实施方式如下:

public class SendConfirmationEmail : Listener<UserWasUpdated>, IHandleSuccess
{
    private _Event = null;

    public override void Handle(UserWasUpdated _event)
    {
        // Store _event
        _Event = _event;
    }

    public void Finished()
    {
        // Call whatever function on your object
        this.Cleanup()

        // Call whatever is needed on _event
        _Event?.Cleanup();
    }
}

您可以执行以下操作:

var cls = new SendConfirmationEmail();

if (cls is IHandleSuccess _cls)
{
    _cls.Finished();
}

答案 2 :(得分:-1)

您可以使用Type.GetInterfaces()并执行以下操作:

if (listener.GetType().GetInterfaces().Any(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IHandleSuccess<>)))
{
    //
}