无法将基类(数据协定)转换为派生类
Posted
技术标签:
【中文标题】无法将基类(数据协定)转换为派生类【英文标题】:Unable to cast Base class (data contract) to derived class 【发布时间】:2013-04-29 20:30:38 【问题描述】:[DataContract]
public class SearchCriteria
[DataMember]
public string CountryID get; set;
[DataContract]
public class CitySearchCriteria: SearchCriteria
[DataMember]
public string CityID get; set;
我正在 MVC 控制器操作中创建 SearchCriteria 的实例,并尝试 将其转换为 CitySearchCriteria。
SearchCriteria searchCriteria = new SearchCriteria();
searchCriteria.CountryID = "1";
CitySearchCriteria citySearchCriteria = searchCriteria as CitySearchCriteria;
上述语句后的“citySearchCriteria”对象显示为 NULL 值。我期待它显示两个属性,CountryID 和 CityID,CountryID 填充,CityID 为空白......但它将对象设置为 NULL。
这里有什么解决方案? DataContract 对此有什么作用吗?
cmets 建议,您不能将基数转换为派生: 但实际上,在我看来,我已经成功地做到了,它只是在控制器操作中不起作用:
CitySearchCriteria citySearchCriteria = (CitySearchCriteria)Model.SearchCriteria;
这已成功转换,那么为什么在控制器操作中不能使用类似的东西呢?
【问题讨论】:
您不能从 Base 转换为 Derived。反之亦然 请看问题的最后两段 再次检查马丁的答案(第一个例子)。 【参考方案1】:你不能这样投射!
如果您执行new
,您将创建一个特定大小的新内存对象。在您的情况下,new SearchCriteria()
创建了一个新的内存对象,其大小足以容纳一个字符串,仅此而已。
在最后一行中,您执行searchCriteria as CitySearchCriteria
尝试将searchCriteria
中的对象转换为更大的类型CitySearchCriteria
。但这是不可能的。您正在尝试将包含 1 个字符串的内存对象“转换”为可以包含 2 个字符串的内存对象。但是强制转换不会转换新的内存对象。新字符串的值是多少?它只是在水下检查您的引用searchCriteria
是否已经包含CitySearchCriteria
类型的对象。在您的情况下:它没有(对象的类型为SearchCriteria
)并返回null
。
所以...下一个示例有效(因为 CitySearchCriteria 已经创建)。这也是您的解决方案:
SearchCriteria searchCriteria = new CitySearchCriteria();
CitySearchCriteria citySearchCriteria = searchCriteria as CitySearchCriteria;
这不起作用(因为尚未创建 CitySearchCriteria)。这是你的情况:
SearchCriteria searchCriteria = new SearchCriteria();
CitySearchCriteria citySearchCriteria = searchCriteria as CitySearchCriteria;
这与下一个示例相同。 这确实有效(因为 SearchCriteria 已经创建):
object o = new SearchCriteria();
SearchCriteria searchCriteria = o as SearchCriteria;
这不是(因为尚未创建 SearchCriteria)::
object o = new object();
SearchCriteria searchCriteria = o as SearchCriteria;
为了记录:我总是使用直接转换,而不是使用 as
的转换,除非您想明确测试对象是否属于该类型。
【讨论】:
它只是无法转换,因为根据他的实现,转换无法从基类转换为派生类。反之亦然。 我想这正是我所说的......不是吗?还是我错过了你的意思?我的文字中哪个例子不正确? 是的,第三个会起作用。对象可以包含任何类型。只要它拥有该类型,您就可以将其转换为任何类型。另一个例子是:object o = "Hello"; string s = o as string;
为什么你认为它不起作用?
我不是这个意思。 他的问题的解决方案在哪里?
解决方案是示例#1。【参考方案2】:
每个人都已经(并且正确地)告诉过您,您根本无法从 Base 转换为 Derived,但在我看来,您仍然不明白为什么该行在您的另一块代码中起作用的原因:
CitySearchCriteria citySearchCriteria = (CitySearchCriteria)Model.SearchCriteria;
我认为您对实例的“类型”有点困惑。你没有发布模型的定义,但我认为你有这样的东西:
public SearchCriteria SearchCriteria;
这并不意味着 SearchCriteria 总是包含 SearchCriteria 的实例,而只是它包含可以转换为 SearchCriteria 的类型的实例。在您的情况下,它可以包含 SearchCriteria 或 CitySearchCriteria 的实例。我想在你的代码中的某个地方你会发现类似的东西:
Model.SearchCriteria = new CitySearchCriteria();
这就是正确执行 yor cast 的原因。您可以看到该实例确实是一个 CitySearchCriteria(而不仅仅是 SearchCriteria 的一个实例),它在强制转换之前执行此代码:
MessageBox.Show(Model.SearchCriteria.GetType().FullName);
为了更好地理解,您可以尝试在工作转换之前修改 SearchCriteria 中的值,如下所示,结果发现转换不再起作用:
Model.SearchCriteria = new SearchCriteria();
MessageBox.Show(Model.SearchCriteria.GetType().FullName);
CitySearchCriteria citySearchCriteria = (CitySearchCriteria)Model.SearchCriteria;
【讨论】:
谢谢你,是的,你是对的,我对此有很多困惑。这些细节已经澄清了这一点,我可以看到我在编码时错在哪里。谢谢【参考方案3】:您可以创建 CitySearchCriteria,并将其转换为 SearchCriteria。这样你只能看到 CountryId。稍后,您可以将其转换回 CitySearchCriteria,并查看 CountryId 和 CityId。
这与 DataContract 无关。在您的情况下,解决方案是创建 CitySearchCriteria 并将其转换为 SearchCriteria(如果需要)。
【讨论】:
我发现了两个类似的问题:***.com/questions/988658/…和***.com/questions/9885644/… 问题是,我的视图期待一个“SearchCriteria”对象,因为它是从多个地方调用的,根据调用控制器和操作,它可以有“CitySearchCriteria”、“StateSearchCriteria”等。另外,我已经在我的视图中成功地做到了这一点,比如 CitySearchCriteria citySearchCriteria = (CitySearchCriteria)Model.SearchCriteria;并且工作正常,那么为什么不在控制器操作中呢?以上是关于无法将基类(数据协定)转换为派生类的主要内容,如果未能解决你的问题,请参考以下文章