C# 为什么我不能在其具体实现中键入cast接口?

C# 为什么我不能在其具体实现中键入cast接口?,c#,interface,casting,C#,Interface,Casting,这是一个非常琐碎的问题,由于我缺乏经验,似乎很烦人,但为什么我不能做这样的事情: public interface INetworkMessage { ... } public class NetworkDataMessage : INetworkMessage { ... } public void ParseMessage (INetworkMessage message) { Type concreteMessageType = message.GetType();

这是一个非常琐碎的问题,由于我缺乏经验,似乎很烦人,但为什么我不能做这样的事情:

 public interface INetworkMessage { ... }
 public class NetworkDataMessage : INetworkMessage { ... }

 public void ParseMessage (INetworkMessage message)
 {
     Type concreteMessageType = message.GetType();
     var concreteMessageInstance = message as concreteMessageType;
     ...
     // Now in theory I could work with a concrete type?
 }

只能使用
as
强制转换为编译时指定的类型(直接或通过泛型)。你的代码无法编译


由于您在编译时不知道什么是
concreteMessageType
,因此也不能使用
concreteMessageInstance
(如果可以进行这种转换),由于编译器需要知道您将使用的方法/属性/字段等。

您只能使用
as
强制转换为您在编译时指定的类型(直接或通过泛型)。你的代码无法编译


由于您在编译时不知道什么是
concreteMessageType
,因此也不能使用
concreteMessageInstance
(如果可以进行这种转换),因为编译器需要知道您将使用的方法/属性/字段等。

回答您的问题:您可以使用强制转换操作和编译时类型名称直接强制转换对象:

var concreteMessageInstance = (NetworkDataMessage)message; //may throw InvalidCastException for different implementation of INetworkMessage

但是:如果需要接口的具体实现,您应该重新考虑您的设计。接口的整体思想是细节无关紧要——也许你试图在具体类型上做的事情应该被移动到接口中?或者您应该直接使用具体类型,并跳过界面?两者都是你应该考虑的设计决策。


如果您希望能够动态地强制转换到接口的任何具体实现并调用某些操作,那么您肯定应该将操作从具体类型移动到接口。强制转换只会增加额外的开销,设计良好的应用程序从一开始就在接口定义中有这样的操作。

回答您的问题:您可以使用强制转换操作和编译时类型名称直接强制转换对象:

var concreteMessageInstance = (NetworkDataMessage)message; //may throw InvalidCastException for different implementation of INetworkMessage

但是:如果需要接口的具体实现,您应该重新考虑您的设计。接口的整体思想是细节无关紧要——也许你试图在具体类型上做的事情应该被移动到接口中?或者您应该直接使用具体类型,并跳过界面?两者都是你应该考虑的设计决策。


如果您希望能够动态地强制转换到接口的任何具体实现并调用某些操作,那么您肯定应该将操作从具体类型移动到接口。cast只会增加额外的开销,设计良好的应用程序从一开始就在接口定义中有这样的操作。

我最终以自己的方式遵循了David的建议:

public void ParseMessage<T> (INetworkMessage message) where T : INetworkMessage
 {
   // So now I can do
   var concreteInstance = (T)message;
}
public void ParseMessage(INetworkMessage message),其中T:INetworkMessage
{
//所以现在我可以做了
var concreteInstance=(T)消息;
}

我最终以自己的方式遵循了大卫的建议:

public void ParseMessage<T> (INetworkMessage message) where T : INetworkMessage
 {
   // So now I can do
   var concreteInstance = (T)message;
}
public void ParseMessage(INetworkMessage message),其中T:INetworkMessage
{
//所以现在我可以做了
var concreteInstance=(T)消息;
}

您可以,但通常不应该。如果你必须这样做,那通常是你的设计有问题的迹象。如果支持类型不是您期望的类型,那么尝试这样做会带来风险。因为
INetworkMessage
不一定是
NetworkDataMessage
,它可以是它的任何实现,那么您如何知道要转换到哪个具体类型?@RonBeyer但GetType()不返回确切的具体类型?@David再次查看代码,他尝试使用
GetType
获取类型,然后使用
as
将其转换为变量。这段代码不会编译。它不是伪代码,
concreteMessageType
是一个变量。@eYe:确切地说,这是一个什么的例子?您需要考虑系统的体系结构,并确定此方法需要做什么,以及它如何适合您的整个系统。如果该方法需要
NetworkDataMessage
的实例,则接受该类型的参数。如果它需要
INetworkMessage
的实例,则接受该类型的参数。你在问题中所问的是解决一个问题的症状,你本来不应该有这个问题。你可以,但一般来说你不应该。如果你必须这样做,那通常是你的设计有问题的迹象。如果支持类型不是您期望的类型,那么尝试这样做会带来风险。因为
INetworkMessage
不一定是
NetworkDataMessage
,它可以是它的任何实现,那么您如何知道要转换到哪个具体类型?@RonBeyer但GetType()不返回确切的具体类型?@David再次查看代码,他尝试使用
GetType
获取类型,然后使用
as
将其转换为变量。这段代码不会编译。它不是伪代码,
concreteMessageType
是一个变量。@eYe:确切地说,这是一个什么的例子?您需要考虑系统的体系结构,并确定此方法需要做什么,以及它如何适合您的整个系统。如果该方法需要
NetworkDataMessage
的实例,则接受该类型的参数。如果它需要
INetworkMessage
的实例,则接受该类型的参数。你在问题中所问的是解决一个问题的症状,而这个问题本来就不应该出现。但是这对你有什么帮助呢?投t真的不能做更多的事情,但这对你有什么帮助呢?你不可能通过投t来做更多的事情。