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