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

Jun*_*ior 2 c#

我有以下界面

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

以下课程

public abstract class Listener<T> where T : Event
{
    public abstract void Handle(T _event);
}
Run Code Online (Sandbox Code Playgroud)

以下类扩展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)
    {
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

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

public class ScheduleOriantation: Listener<UserWasUpdated>
{
    public override void Handle(UserWasUpdated _event)
    {
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

应用程序启动时,我的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)
        {
            // ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,这条线IHandleSuccess<>给了我一个错误

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

由于泛型参数将始终扩展Event类,我还尝试将代码更改为以下内容

listener.Handle(_event);

if (listener is IHandleSuccess<Event> _listener)
{
    _listener.Finished(_event, listener);
}
Run Code Online (Sandbox Code Playgroud)

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

第二个参数无法转换Listener<T>Listener<Event>

我该如何正确修复此错误?

Sco*_*ain 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)
        {
            // ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个例子,如果Announce不是通用的

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)
        {
            // ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @MikeA请阅读[bodin的回答](/sf/answers/3702204481/)他做了一些好点,比如传递`cls` in unessesary,在你使用`listener`的函数中的任何地方void Finished(T _event,Listener <T> listener);`函数可以用简单的`this`调用替换. (2认同)

小智 5

此代码不起作用

var cls = new SendConfirmationEmail();

if (cls is IHandleSuccess<Event> _cls)
{
    _cls.Finished(_event, cls);
}
Run Code Online (Sandbox Code Playgroud)

因为clsSendConfirmationEmail()实现的类型Listener<UserWasUpdated>而是_cls被铸造的类型IHandleSuccess<Event>.该函数需要_cls.Finished()一个listener类型的参数Listener<Event>,而不是Listener<UserWasUpdated>

你的功能有Finished(UserWasUpdated _event, Listener<UserWasUpdated> listener)什么用?查看您使用它的方式,您可以删除参数listenerc并使用this以下内容引用当前侦听器:

所以界面看起来像这样:

public interface IHandleSuccess<T> where T : Event
{
    void Finished(T _event);
}
Run Code Online (Sandbox Code Playgroud)

和这样的实现:

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()
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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);
}
Run Code Online (Sandbox Code Playgroud)

如果您希望能够这样做,则需要使界面非通用.如果_event对象cls事先为您的对象所知,您可以将其存储并在Finished()调用中使用它,如下所示:

接口:

public interface IHandleSuccess
{
    void Finished();
}
Run Code Online (Sandbox Code Playgroud)

和这样的实现:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以这样做:

var cls = new SendConfirmationEmail();

if (cls is IHandleSuccess _cls)
{
    _cls.Finished();
}
Run Code Online (Sandbox Code Playgroud)