无法将基类(数据契约)强制转换为派生类

本文关键字:转换 派生 契约 基类 数据 | 更新日期: 2023-09-27 18:12:19

[DataContract]
public class SearchCriteria
{
    [DataMember]
    public string CountryID { get; set; }    
}
[DataContract]
public class CitySearchCriteria: SearchCriteria
{
    [DataMember]
    public string CityID { get; set; }
}

我正在创建一个实例的搜索标准在我的MVC控制器的动作,并试图将其转换为CitySearchCriteria。

SearchCriteria searchCriteria = new SearchCriteria();
searchCriteria.CountryID = "1";
CitySearchCriteria citySearchCriteria = searchCriteria as CitySearchCriteria;

上面语句后面的"citySearchCriteria"对象显示NULL值。我期待它显示两个属性,CountryID和CityID与CountryID填充,和CityID空白…但它将对象设置为NULL。

这里的解决方案是什么?有数据合约做任何与此?

注释提示,不能将基类转换为派生类:但实际上,我已经在我的视图中成功地做到了这一点,它只是在控制器动作中不起作用:

CitySearchCriteria citySearchCriteria = (CitySearchCriteria)Model.SearchCriteria;

这是转换成功,所以为什么不类似的事情在控制器动作工作?

无法将基类(数据契约)强制转换为派生类

不能这样强制转换!

如果您执行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强制转换,除非您想显式地测试对象是否属于该类型。

每个人都已经(正确地)告诉你,你根本不能从Base转换到Derived,但在我看来,你仍然不明白为什么这一行在你的另一段代码中工作:

CitySearchCriteria citySearchCriteria = (CitySearchCriteria)Model.SearchCriteria;

我认为你对实例的"类型"是什么有点困惑。你没有发布模型的定义,但我认为你有这样的东西:

public SearchCriteria SearchCriteria;

这并不意味着SearchCriteria总是包含SearchCriteria的实例,而只是它包含可以转换为SearchCriteria的类型的实例。在您的示例中,它可以包含SearchCriteria或CitySearchCriteria的实例。我想在你的代码中你会发现这样的东西:

Model.SearchCriteria = new CitySearchCriteria();

,这是允许正确执行强制转换的原因。您可以看到实例确实是一个CitySearchCriteria(而不仅仅是SearchCriteria的一个实例),它在强制转换之前执行以下代码:

MessageBox.Show(Model.SearchCriteria.GetType().FullName);

为了更好地理解,您可以尝试在工作强制转换之前修改SearchCriteria中的值,如下所示,结果只会发现强制转换不再工作:

Model.SearchCriteria = new SearchCriteria();
MessageBox.Show(Model.SearchCriteria.GetType().FullName);
CitySearchCriteria citySearchCriteria = (CitySearchCriteria)Model.SearchCriteria;

您可以创建CitySearchCriteria,并将其转换为SearchCriteria。这样您只能看到CountryId。稍后,您可以将其转换回CitySearchCriteria,并查看CountryId和CityId。

这与datcontract无关。在这种情况下,解决方案是创建CitySearchCriteria并将其转换为SearchCriteria(如果需要的话)。