C#抽象泛型类型:不能隐式转换Type' A:B'到' B'

时间:2014-05-30 09:22:41

标签: c# generics

我可能需要一些帮助来进行编译。我只想传递类类型(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>'

难道不可能吗?

3 个答案:

答案 0 :(得分:4)

你想要的是协方差。有一些限制:

  • 只有界面可以使用协方差,而不是类
  • 如果泛型类型参数未在任何方法的输入中使用,则只能使其成为协变型。因此它只能用于属性和方法的 return 值。

您可以像这样定义协变界面:

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

但是请注意,如果你有一个采用TArgs类型参数的方法,这将无法编译。提出示例为什么允许这会破坏类型安全性是相对简单的(例如,参见Jon Skeet对this question的回答)。如果这是您的要求,则必须重新考虑您的设计。

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

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

但不是:

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

答案 1 :(得分:1)

添加界面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);

答案 2 :(得分:0)

您需要通过为TArgs通用参数指定covariant来创建out keyword接口以允许此操作:

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