C# System.InvalidCastException:无法将x类型的对象强制转换为y类型

C# System.InvalidCastException:无法将x类型的对象强制转换为y类型,c#,generics,casting,C#,Generics,Casting,我有一个自定义的消息传递系统,我正试图转换,以便它可以支持插件 这个系统有生产者和消费者。 两者都必须指定它们产生或使用的消息类型 对于使用者,要实现的接口是 IConsumer<AMessage> 而AMessage是一个抽象类。 IConsumer和AMessage都位于主(核心)程序集中 现在,在内核中,它加载了插件并扫描并找到了消费者,我想将消费者链接到消息传递系统中 为了简化这里的事情,我只是尝试将消费者放在一个变量中: IConsumer<AMessage>

我有一个自定义的消息传递系统,我正试图转换,以便它可以支持插件

这个系统有生产者和消费者。 两者都必须指定它们产生或使用的消息类型

对于使用者,要实现的接口是

IConsumer<AMessage>
而AMessage是一个抽象类。 IConsumer和AMessage都位于主(核心)程序集中

现在,在内核中,它加载了插件并扫描并找到了消费者,我想将消费者链接到消息传递系统中

为了简化这里的事情,我只是尝试将消费者放在一个变量中:

IConsumer<AMessage> consumer = IConsumer<AMessage> new FileProcessor();
有流量。来自:

public Channel<T> From<T>(IProducer<T> producer) where T : AMessage
{
    ...
}
来自(IProducer制作人)的公共频道,其中T:AMessage
{
...
}
和频道。至:

public class Channel<T> where T : AMessage 
{

   public Channel<T> To(IConsumer<T> consumer){
      ...
   }
}
公共类频道,其中T:AMessage
{
公共频道至(i消费者){
...
}
}
因此,生产者为消费者定义了T的类型

--edit1--

--edit2--

之所以需要向下转换,是因为我试图从核心系统中的JSON定义重建通道

因此,消费者(和生产者)是从插件程序集动态构建的,并添加到临时字典(当检测到并实例化时):

var consumers=newdictionary();
我不能在这里为消费者使用IConsumer,因为T不一定对所有消费者都一样

然后在构建通道时,我将根据消费者的id(字典的键)查找消费者,并将其提供给通道的to(…)方法。这会失败,因为字典包含IPProcessor,动态构造的通道具有“To”签名,即
公共通道To(IConsumer consumer)

--edit2--

--解决方案--

感谢Luaan(见评论),我找到了以下解决方案:

扫描插件程序集时,我最初将检测到的生产者和消费者存储在
的字典中,现在我将此字典更改为
,从而解决了此铸造问题

感谢所有加入此解决方案的人

@Luaan,我希望我能选择你的答案作为解决方案,但它在评论中

--解决方案--


谢谢

您需要使用
out
关键字将界面标记为:

IConsumer<out AMessage>
这是无效的。从msdn:

逆变 使您能够使用比最初指定的更通用(派生更少)的类型。 您可以将IEnumerable的实例分配给IEnumerable类型的变量。


如果在
IConsumer
界面中,
T
仅在返回值中出现,则可以使界面协变(在.NET 4及更高版本中):

公共接口i消费者
在这种情况下,此初始化将起作用:

IConsumer<AMessage> consumer = new FileProcessor();
IConsumer consumer=new FileProcessor();

但是,如果在方法参数中也使用了
T
,那么您的接口就不能是协变的。这很好,请参见
IList
,例如:如果允许
IList cats=new List()
,您可以调用
cats.Add(new Dog())
,这是不需要的:

您确定
FileProcessor
(可能是为了使用
FileMessages
)而编写的)能够处理任何类型的
AMessage
的传递吗?“FileProcessor”不能只使用任何AMessage,只能使用FileMessage。但这是由系统处理的。当在系统中链接制作者时,将使用制作者的相同消息类型创建频道。然后通道只接受与生产者具有相同AMessage类型的使用者(都是通过泛型完成的)。您收到警告和强制转换异常的事实意味着系统/泛型没有正确处理此问题。如果频道只需要正确类型的使用者,则不必强制转换为常规类型。能否在强制转换周围添加一些代码-告诉我们为什么需要强制转换为常规使用者类型?好吧,这不是一个简单的问题。泛型是编译时和运行时类型安全的,所以您尝试的所有操作都必须失败,因为您破坏了类型安全性。一个简单(虽然不一定是好的)解决方案可能是使用
dynamic
来处理特定的使用者和生产者类型-这允许您将类型解析推迟到运行时,这将使您的代码正常工作。当然,它也引入了许多自身的问题,将工作推迟到运行时意味着更少的编译时检查。我担心称为使用者的东西是否应该将
输出
,而不是
输入,但从表面上看,这正是提问者想要的…@Rawling好吧,没有太多的代码可供使用,所以我不知道他试图实现什么,但这确实使他想要的演员阵容有效消费者确实需要在
中加入
。我将在我的帖子中添加定义。
public Channel<T> From<T>(IProducer<T> producer) where T : AMessage
{
    ...
}
public class Channel<T> where T : AMessage 
{

   public Channel<T> To(IConsumer<T> consumer){
      ...
   }
}
var consumers = new Dictionary<string, IProcessor>();
IConsumer<out AMessage>
IConsumer<AMessage> consumer = (IConsumer<AMessage>)new FileProcessor();
public interface IConsumer<out T>
IConsumer<AMessage> consumer = new FileProcessor();