简体   繁体   English

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

[英]how to check if a class implements and interface with a generic using c#?

I have the following interface 我有以下界面

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

And the following class 以下课程

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

The following class which extends Listener<T> and implements IHandleSuccess<T> 以下类扩展了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)
    {
        // ...
    }
}

Lastly, another listener that extends Listener<T> but does not implement IHandleSuccess<T> 最后,另一个监听Listener<T>扩展了Listener<T>但没有实现IHandleSuccess<T>

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

My SendConfirmationEmail gets class is registered into my IoC container when the application starts up. 我的SendConfirmationEmail获取类在应用程序启动时注册到我的IoC容器中。

I want to check if the resolved instance implements a contract. 我想检查已解析的实例是否实现了合同。 And if it does, I want to call the Finished method. 如果确实如此,我想调用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)
        {
            // ...
        }
    }
}

However, the line IHandleSuccess<> is giving me an error 但是, IHandleSuccess<>行给了我一个错误

Unexpected use of an unbound generic name 意外使用未绑定的通用名称

Since the generic argument will always extend the Event class, I also tried changing the code to the following 由于泛型参数将始终扩展Event类,我还尝试将代码更改为以下内容

listener.Handle(_event);

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

But _listener.Finished(_event, listener) gives me the following error 但是_listener.Finished(_event, listener)给了我以下错误

The second argument cannot convert from Listener<T> to Listener<Event> 第二个参数无法从Listener<T>转换为Listener<Event>

How can I correctly fix this error? 我该如何正确修复此错误?

You already know what the generic type of IHandleSuccess<> will be, it will be T because you declared that you would be receiving Listener<T> 's from the request. 您已经知道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)
        {
            // ...
        }
    }
}

Here is a example if Announce was not generic 这是一个例子,如果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)
        {
            // ...
        }
    }
}

This code doesn't work 此代码不起作用

var cls = new SendConfirmationEmail();

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

Because cls is of type SendConfirmationEmail() which implements Listener<UserWasUpdated> whereas _cls is casted as IHandleSuccess<Event> . 因为cls的类型为SendConfirmationEmail() ,它实现了Listener<UserWasUpdated>_cls则被转换为IHandleSuccess<Event> The function _cls.Finished() expect a parameter listener of type Listener<Event> , not Listener<UserWasUpdated> 函数_cls.Finished()期望一个Listener<Event>类型的参数listener Listener<Event> ,而不是Listener<UserWasUpdated>

What is the use of your function Finished(UserWasUpdated _event, Listener<UserWasUpdated> listener) ? 你的函数有什么用? Finished(UserWasUpdated _event, Listener<UserWasUpdated> listener) Looking at the way you are using it, you could remove the parameterc listener and reference the current listener using this : 查看您使用它的方式,您可以删除parameterc listener并使用this引用当前侦听器:

So the interface would look like this: 所以界面看起来像这样:

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

And the implementation like this: 和这样的实现:

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()
    }
}

To answer you first question, this doesn't work because each use of the generic is a different type: 要回答第一个问题,这不起作用,因为泛型的每次使用都是不同的类型:

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);
}

If you want to be able to do this, you need to make you interface non generic. 如果您希望能够这样做,则需要使界面非通用。 If the _event object is known by your object cls beforehand, you can store it and use it in the Finished() call, like this: 如果事先已知对象cls _event对象,则可以将其存储并在Finished()调用中使用它,如下所示:

Interface: 接口:

public interface IHandleSuccess
{
    void Finished();
}

And the implementation like this: 和这样的实现:

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();
    }
}

You can then do: 然后你可以这样做:

var cls = new SendConfirmationEmail();

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM