c#抽象泛型:不能隐式转换type 'A: B'& # 39; b # 39;

本文关键字:type 泛型 抽象 不能 转换 | 更新日期: 2023-09-27 18:05:48

我可能需要一些帮助来获得这个编译。我只是想传递一个类类型(SuccessEventArgs)作为一个泛型类DebugEvent<TArgs> where TArgs : System.EventArgs的参数,但由于某种原因,这将不工作。

namespace MyInterface
{
    [Serializable]
    public class SuccessEventArgs : System.EventArgs
    {
        public SuccessEventArgs(string data);
        public byte[] GetData();
    }
}
public class DebugEvent<TArgs> where TArgs : System.EventArgs 
{
    // ...
}

// ///////////////////////////////////////////////////////////////////////

public abstract class DebugEventHandler
{
    protected DebugEvent<EventArgs> m_programmingSucceededEvent = null;
}
public class MyDebugEventHandler : DebugEventHandler
{
    override public void InitializeEventHandler(int programmingSuccessCode, int breakepointReachedCode)
    {
        m_programmingSucceededEvent = new DebugEvent<SuccessEventArgs>(ref m_eventSignal, programmingSuccessCode, this);
    }
}

错误信息:

Cannot implicitly convert type 'DebugEvent<SuccessEventArgs>' to 'DebugEvent<System.EventArgs>'

这难道不可能吗?

c#抽象泛型:不能隐式转换type 'A: B'& # 39; b # 39;

你想要的被称为协方差。它有一些限制:

    只有接口可以使用协方差,而不是类
  • 泛型类型参数只有在不用于任何方法的输入时才能成为协变的。所以它只能在属性和方法的返回值中使用。

可以这样定义协变接口:

public interface IDebugEvent<out TArgs> where TArgs : System.EventArgs

但是注意,如果你有一个接受TArgs类型参数的方法,这将无法编译。要想出为什么允许这样做会破坏类型安全的例子相对简单(例如,请参阅Jon Skeet对这个问题的回答)。如果这是您的需求,您将不得不重新考虑您的设计。

为了实际使用它,您必须使用接口类型的变量,而不是具体的类。你可以输入:

IDebugEvent<EventArgs> m_programmingSucceededEvent = new DebugEvent<SuccessEventArgs>();

但不是:

DebugEvent<EventArgs> m_programmingSucceededEvent = new DebugEvent<SuccessEventArgs>();

添加IDebugEvent<out T> where T : EventArgs接口,并有DebugEvent<T> : IDebugEvent<T> where T : EventArgs

那么下面的语句就可以了:

IDebugEvent<EventArgs> m_programmingSucceededEvent = new DebugEvent<SuccessEventArgs>(ref m_eventSignal, programmingSuccessCode, this);

您需要通过为TArgs泛型参数指定out关键字来创建一个协变接口来实现这一点:

public interface IDebugEvent<out TArgs> where TArgs : System.EventArgs
{ /* ... */ }

这只在接口上支持,所以你需要让你的DebugEvent类实现协变接口:

public class DebugEvent<TArgs> : IDebugEvent<TArgs> where TArgs:System.EventArgs 
{ /* ... */ }

这将允许您分配一个类型的实例,该类型的泛型参数类型派生自基本System.EventArgs类型。

IDebugEvent<EventArgs> evt = new DebugEvent<SuccessEventArgs>();