简体   繁体   English

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

[英]System.InvalidCastException: Unable to cast object of type x to type y

I have a custom messaging system which I am trying to convert so it can support plugins. 我有一个自定义消息系统,我试图转换,所以它可以支持插件。

The system has producers and consumers. 该系统有生产者和消费者。 Both must specify the type of message they produce or consume. 两者都必须指定它们生成或使用的消息类型。

For consumers the Interface to be implemented is 对于消费者来说,要实现的接口是

IConsumer<AMessage>

I have a consumer in a plugin dll which implements this Interface: 我有一个插件dll中的消费者,它实现了这个接口:

FileProcessor : IConsumer<FileMessage>

With

FileMessage : AMessage

And AMessage is an abstract class. 而AMessage是一个抽象类。 Both IConsumer and AMessage are in the main (Core) assembly. IConsumer和AMessage都在主(Core)程序集中。

Now, in the core, which loaded the plugin and scanned & found the consumers I want to link the consumers into the messaging system. 现在,在核心中,它加载了插件并扫描并找到了我希望将消费者链接到消息系统的消费者。

To simplify things here I just try to put the consumer in a variable: 为了简化这里的事情,我只是尝试将消费者放在一个变量中:

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

I get a warning in VS: 我在VS中收到警告:

Suspicious cast:there is no type in the solution which is inherited from both 'TestPlugin.FileProcessor' and 'Core.IConsumer'. 可疑演员:解决方案中没有类型继承自'TestPlugin.FileProcessor'和'Core.IConsumer'。

And when I execute I get 当我执行时,我得到了

System.InvalidCastException: Unable to cast object of type 'TestPlugin.FileProcessor' to type 'Core.IConsumer`1[Core.AMessage]'. System.InvalidCastException:无法将类型为'TestPlugin.FileProcessor'的对象强制转换为'Core.IConsumer`1 [Core.AMessage]'。

Why does this cast fail? 为什么这个演员会失败? How can I solve this? 我怎么解决这个问题?

--edit1-- --edit1--

based on comments, here is the full definition of IProducer and IConsumer: 根据评论,这里是IProducer和IConsumer的完整定义:

public interface IProducer<out T> : IProcessor where T : AMessage
{
    event MessageSender<T> SendMessage;
}

public interface IConsumer<in T> : IProcessor where T : AMessage
{
    ProcessResult ProcessBean(T bean);
}

when Producers are linked in the system, they define T, after that only consumers with the same type of T can be linked to that producer. 当生产者在系统中链接时,他们定义T,之后只有具有相同类型T的消费者可以链接到该生产者。 For example: 例如:

var channel = flow.From(FileProducer).To(FileConsumer);

With flow.From: 随着flow.From:

public Channel<T> From<T>(IProducer<T> producer) where T : AMessage
{
    ...
}

and channel.To: 和频道。要:

public class Channel<T> where T : AMessage 
{

   public Channel<T> To(IConsumer<T> consumer){
      ...
   }
}

So the producer defines the type of T for the consumers. 因此,生产者为消费者定义了T的类型。

--edit1-- --edit1--

--edit2-- --edit2--

The need for the down-cast is because I am trying to reconstruct the channels from an JSON definition in the Core system. 向下转换的需要是因为我试图从Core系统中的JSON定义重建通道。

So Consumers (and Producers) are dynamically constructed from the plugins assemblies and added to a temporary dictionary (when detected and instantiated): 因此,消费者(和生产者)是从插件程序集动态构造的,并添加到临时字典中(当检测到并实例化时):

var consumers = new Dictionary<string, IProcessor>();

I cannot use IConsumer here for the consumers since T is not necessarily the same for all consumers. 我不能在这里为消费者使用IConsumer,因为对于所有消费者来说T不一定相同。

Then when building the Channels, I'll lookup the consumer by it's id (key of dictionary) and provide it to the To(...) method of the channel. 然后在构建频道时,我将通过它的id(字典的键)查找消费者,并将其提供给频道的To(...)方法。 That fails because the dictionary holds IProcessor and the dynamically constructed channel has a "To" signature of public Channel<T> To(IConsumer<T> consumer) . 这失败是因为字典保存了IProcessor,并且动态构造的通道具有public Channel<T> To(IConsumer<T> consumer)的“To”签名。

--edit2-- --edit2--

--solution-- - 解 -

Thanks to Luaan (see comments) I reached to the following solution: 感谢Luaan(见评论)我达到了以下解决方案:

When scanning the plugin assemblies I originally stored the detected Producers and Consumers in a dictionary of <string, IProcessor> , now I changed this dictionary to <string, dynamic> which solved this casting issue! 当扫描插件程序集时,我最初将检测到的生产者和消费者存储在<string, IProcessor>的字典中,现在我将这个字典改为<string, dynamic> ,这解决了这个转换问题!

Thanks to all who added to getting to this solution! 感谢所有为此解决方案添加的人!

@Luaan, I wished I could select your answer as the solution, but it is in a comment... @Luaan,我希望我能选择你的答案作为解决方案,但它在评论中......

--solution-- - 解 -

Thanks! 谢谢!

You need to mark your interface as covariant with the out keyword: 您需要将您的界面标记为与out关键字的协变

IConsumer<out AMessage>

This means you can pass a more derived type than the one specified, so you can use a FileMessage which derives from AMessage . 这意味着可以通过一个更派生类型规定以外的,所以可以使用一个FileMessage从派生AMessage

Seeing your edits, you don't need covariance but contravariance ( IConsumer<in AMessage> ) but then this cast: 看到你的编辑,你不需要协方差而是逆变( IConsumer<in AMessage> )但是这个演员:

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

isn't valid. 无效。 From msdn: 来自msdn:

Contravariance Enables you to use a more generic (less derived) type than originally specified. Contravariance使您可以使用比最初指定的更通用(更少派生)的类型。 You can assign an instance of IEnumerable<Base> to a variable of type IEnumerable<Derived>. 您可以将IEnumerable <Base>的实例分配给IEnumerable <Derived>类型的变量。

If in your IConsumer<T> interface the T occurs only in return values, then you can make your interface covariant (in .NET 4 and above): 如果在您的IConsumer<T>接口中, T仅出现在返回值中,那么您可以使接口协变(在.NET 4及更高版本中):

public interface IConsumer<out T>

In this case this initialization will work: 在这种情况下,此初始化将起作用:

IConsumer<AMessage> consumer = new FileProcessor();

But if T is used in method parameters as well, then your interface cannot be covariant. 但是如果T也用在方法参数中,那么你的界面就不能协变。 Which is good so, see IList<T> , for example: If IList<Animal> cats = new List<Cat>() would be allowed, you could call cats.Add(new Dog()) , which is not desired. 哪个好,请参阅IList<T> ,例如:如果IList<Animal> cats = new List<Cat>()将被允许​​,您可以调用cats.Add(new Dog()) ,这是不需要的。 :) :)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 System.InvalidCastException:无法转换类型的对象 - System.InvalidCastException: Unable to cast object of type System.InvalidCastException: &#39;无法将类型为 &#39;ClassName&#39; 的对象转换为类型 InterfaceName&#39;。 - System.InvalidCastException: 'Unable to cast object of type 'ClassName' to type InterfaceName'.' System.InvalidCastException:无法将类型为“ System.Object”的对象转换为类型为“ System.IO.StreamWriter” - System.InvalidCastException: Unable to cast object of type 'System.Object' to type 'System.IO.StreamWriter' 发生类型为&#39;System.InvalidCastException&#39;的未处理异常…无法将类型为&#39;System.String&#39;的对象转换为类型 - unhandled exception of type 'System.InvalidCastException' occurred…Unable to cast object of type 'System.String' to type System.InvalidCastException: &#39;无法将&#39;System.Windows.Forms.TextBox&#39;类型的对象转换为&#39;System.IConvertible&#39; - System.InvalidCastException: 'Unable to cast object of type 'System.Windows.Forms.TextBox' to type 'System.IConvertible System.InvalidCastException:无法将类型为System.DBNull的对象转换为类型为System.String的对象 - System.InvalidCastException: Unable to cast object of type 'System.DBNull' to type 'System.String' 错误:System.InvalidCastException:无法将“System.Byte”类型的对象转换为“System.Int32”类型 - Error: System.InvalidCastException: Unable to cast object of type 'System.Byte' to type 'System.Int32' System.InvalidCastException:“无法将“System.Double”类型的 object 转换为“System.Single”类型。 - System.InvalidCastException: 'Unable to cast object of type 'System.Double' to type 'System.Single'.' System.InvalidCastException:“无法将“System.Random”类型的对象转换为“System.IConvertible”类型。” - System.InvalidCastException: "Unable to cast object of type 'System.Random' to type 'System.IConvertible'." System.InvalidCastException: &#39;无法将类型为&#39;System.TimeSpan&#39;的对象转换为类型&#39;System.IConvertible&#39; - System.InvalidCastException: 'Unable to cast object of type 'System.TimeSpan' to type 'System.IConvertible'
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM