Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 无法转换泛型类型参数_C# - Fatal编程技术网

C# 无法转换泛型类型参数

C# 无法转换泛型类型参数,c#,C#,我需要调用一个接受接口作为参数的方法。作为参数使用的对象实现了接口,但是仍然会出现编译错误。我做错了什么 public class ViewModel { public ViewModel() { QueueManager<CFMessage<CFQueueItem>, CFQueueItem> q = new QueueManager<CFMessage<CFQueueItem>, CFQueueItem>();

我需要调用一个接受接口作为参数的方法。作为参数使用的对象实现了接口,但是仍然会出现编译错误。我做错了什么

public class ViewModel 
{
    public ViewModel()
    {
        QueueManager<CFMessage<CFQueueItem>, CFQueueItem> q = new QueueManager<CFMessage<CFQueueItem>, CFQueueItem>();
        DoSomething(q);     // This line does not compile:  Cannot convert from QueueManager<CFQueueItem> to QueueManager<IQueueItem>
    }

    public void DoSomething(QueueManager<IQueueMessage<IQueueItem>, IQueueItem> queueManager)
    {

    }
}

public interface IQueueMessage<T> where T : IQueueItem
{
    int ID { get; set; }
}

public interface IQueueItem
{
    int ID { get; set; }
}

public class CFMessage<CFQueueItem> : IQueueMessage<CFQueueItem> where CFQueueItem : IQueueItem
{
    public int ID { get; set; }
}

public class CFQueueItem : IQueueItem
{
    public int ID { get; set; }
}

public class QueueManager<T, Q>
    where T : IQueueMessage<Q>
    where Q : IQueueItem
{

}
公共类视图模型
{
公共视图模型()
{
QueueManager q=新的QueueManager();
DoSomething(q);//此行未编译:无法从QueueManager转换为QueueManager
}
公共无效DoSomething(队列管理器队列管理器)
{
}
}
公共接口IQueueMessage,其中T:IQueueItem
{
int ID{get;set;}
}
公共接口IQueueItem
{
int ID{get;set;}
}
公共类CFMessage:IQueueMessage,其中CFQueueItem:IQueueItem
{
公共int ID{get;set;}
}
公共类CFQueueItem:IQueueItem
{
公共int ID{get;set;}
}
公共类队列管理器
其中T:IQueueMessage
Q:IQueueItem在哪里
{
}

您可以使用概念解决问题,使用关键字
out
将接口
IQueueMessage
定义为协变:

public interface IQueueMessage<out T> where T : IQueueItem
{
}
然后,您可以将此接口用于方法
DoSomething

public void DoSomething(IQueueManager<IQueueMessage<IQueueItem>, IQueueItem> queueManager)
{
}
public void DoSomething(IQueueManager queueManager)
{
}
您的代码将成功编译:

public ViewModel()
{
    var q = new QueueManager<CFMessage<CFQueueItem>, CFQueueItem>();
    DoSomething(q);
}
公共视图模型()
{
var q=新的队列管理器();
剂量测定法(q);
}

尝试使方法通用;即使无法使接口变为协变,这也将起作用:

public void DoSomething<TMessage, TItem>(QueueManager<TMessage, TItem> queueManager) 
    where TMessage : IQueueMessage<TItem>
    where TItem : IQueueItem
{ 
     //...
} 
public void DoSomething(队列管理器)
其中t消息:IQueueMessage
地点:IQueueItem
{ 
//...
} 

您应该考虑使用<代码> var >代码>复杂的变量声明。要传递的对象实现<代码> QuealEngAsAs/COD>,而不是<代码> QuealEngAsAs/COD>。第一种类型不是第二种类型的子类型,就像
List
List
@JonathonReinhart的子类型一样-我会的that@phoog对不起,我不明白你为什么这么说。CFMessage实现IQueueMessage,CFQueueItem实现IQueueItem,这是该方法所期望的。@Sam ok,简而言之:您不能将
列表
传递给期望
列表
的方法,因为该方法可以执行以下操作:
列表。添加(1)
,这将失败。类似地,
DoSomething
可以将任何实现IQueueManager的类型传递给其queueManager参数(如果它有类似于
ManageItem(IQueueManager)的方法)
;如果queueManager对象实际上是一个queueManager,但该方法传递了一个XYQueueItem,则会出现运行时错误。编译器在编译时不允许这样做,因此不需要在运行时进行类型检查……除非接口不是安全协变的,在这种情况下,它将不会使用
out
关键字进行编译。@phoog:是的,如果这里的泛型类型不是结果类型,那么你是对的。非常感谢你,我永远不会明白这一点。我仍然不知道为什么它会起作用,但它确实起作用。这似乎是一个显而易见的解决方案,但我的ViewModel类上的QueueManager属性实际上是一个依赖属性。我刚刚将这个示例简化为举例说明问题。@Sam在这种情况下,我想你有几个选择。我能想到的三个方法是使用协变接口,正如Cuong Le所建议的那样,将ViewModel类设置为泛型,或者采用强制转换。如果接口允许,协变将是一种方法。
public void DoSomething<TMessage, TItem>(QueueManager<TMessage, TItem> queueManager) 
    where TMessage : IQueueMessage<TItem>
    where TItem : IQueueItem
{ 
     //...
}