[英]Downcasting in C#
我正面临一个我不知道如何解决的问题,希望社区可以提供帮助。
我正在编写一个管理“Lead”对象的应用程序。 (这些是销售线索。)我的程序的一部分将从文本文件中导入潜在客户。 现在,文本文件包含许多潜在的潜在客户,其中一些我想要导入,其中一些我不会。
为了便于编程(和使用),我将文本文件解析为List <Lead>对象,并使用DataGridView通过设置DataGridView的DataSource属性来显示潜在客户。
我想要做的是在网格中添加一个名为“导入”的列,其中包含一个复选框,用户可以选中该复选框以指示是否应导入每个导联。
我的第一个想法是从Lead派生一个班级:
public Class LeadWithImportCheckbox : Lead
{
bool bImport = false;
public bool Import { get { return bImport;} set { bImport = value;} } }
但是,解析引擎返回Lead对象列表。 我无法将潜在客户转向LeadWithImportCheckbox。 这失败了:
LeadWithImportCheckbox newLead = (LeadWithImportCheckbox)LeadFromParsingEngine;
这是一个无效的演员表。
我看到的另一个选项是为LeadWithImportCheckbox创建一个构造函数:
public LeadWithImportCheckbox(Lead newlead) { base.Property1 = newlead.Property1; base.Property2 = newlead.Property2; .... base.Property_n = newlead.Property_n; }
出于两个原因,这是有问题的。
一,Lead对象有几十个属性,编写这个构造函数是PITA。
但更糟糕的是,如果我更改了Lead的底层结构,我需要记住返回并更改LeadWithImportCheckbox的构造函数。 这对我的代码维护是一个危险。
有没有更好的方法来实现我的目标?
或者,为了避免PITA方面,使用反射......(试试这个...)
编辑:使用属性,而不是我最初写的字段...
public class NewLead : Lead
{
public bool Insert;
public NewLead(Lead lead, bool insert)
{
Insert = insert;
foreach (PropertyInfo pi in typeof(Lead).GetProperties())
GetType().GetProperty(pi.Name).SetValue
(this, pi.GetValue(lead,null), null);
}
}
public class LeadListItem
{
public Lead Lead { get; set; }
public bool ShouldImport { get; set; }
}
即,不要复制Lead对象的内容,只需在新的LeadListItem对象中存储对它的引用,这会在原始对象“外部”添加额外信息。
如果您希望Lead的属性出现在网格中,几乎可以肯定有一种方法可以实现。 为什么不问这个问题,而不是低估我告诉你这个问题的正确答案!
您可能错过了几个选项:
您要做的是在网格上显示复选框列,而不是与Lead对象完全相关。 您可以使用标记的列(以及可能的原始列表)来构建一组新的List,它将作为您的导入列表。
然后处理你想用新创建的List做的任何事情。
编辑:使用列表时要注意的一件事是,每个类对象实际上只是指向类的指针,因此如果您使用原始列表并执行以下操作:
List<Lead> Importable = new List<Lead>();
for(int i=0, i++, i<viewGrid.Count)
if(viewGrid[i].CheckedColumn.Checked)
Importable.Add(OriginalList[i]);
这些对象将存在于两个列表中,如果您在任一列表上编辑Lead的数据,则两者都将被更改。
如果要向下转换的对象确实是该类型的对象,则只能向下转换。
解决问题的更简单方法是使用DisplayLead类,例如:
public class DisplayLead {
Lead lead;
bool bImport;
}
这也可以帮助您将存储的数据与GUI中的表示分开。
我不能低估它不是的东西。 如果对象被实例化为Lead
,那么它不能被转发到任何派生类。 如果它被实例化为LeadWithImportCheckbox
,然后作为Lead
返回到您的代码,那么您可以向下转换它。
Protip:运行时使用is
运算符检查类型。
有很多方法可以做到这一点,但由于你说的话,“正确”的方式会突然出现,这里:
为了便于编程(和使用),我将文本文件解析为List对象,并使用DataGridView通过设置DataGridView的DataSource属性来显示引线。
我想要做的是在网格中添加一个名为“导入”的列,其中包含一个复选框,用户可以选中该复选框以指示是否应导入每个导联。
您的Lead
对象本身就很好,并且您想要为其附加一些元数据 - 您不希望创建另一个Lead
分类(即LeadWithImportCheckbox
类)。
所以,在你的情况下,最好的方法是有一个这样的类:
public class LeadInfo
{
private Lead lead;
private bool shouldImport;
public LeadInfo(Lead lead)
{
this.lead = lead;
this.ShouldImport = false;
}
public bool ShouldImport
{
get { return shouldImport; }
set { shouldImport = value; }
}
}
当您想要在列表中添加更多元数据时,这将很好地扩展,例如,如果您想每周向自己发送有关它们的电子邮件提醒。
我已经看过很多次列出的正确解决方案我觉得它再次发布了,但最好的办法是为Lead对象编写一个包含import标志的包装器。
如果Lead对象的属性未出现在GridView中,因为您正在对对象进行数据绑定,则写入镜像包装器对象上的Lead属性的passthrough属性。
问题是您希望向用户显示的内容不是数据模型的固有部分。 答案是在将数据呈现给用户之前将数据包装起来,这样您就可以控制他们看到的内容而无需更改基础模型。
如果您担心Lead对象将来会改变很多次以至于对包装器的更改会很麻烦,您可以查看基于Lead对象的动态代码生成,该对象会自动生成一个包含相同字段的包装器对象。 Lead对象加上导入标志。 坦率地说,这比你可能需要的东西要多得多。
作为一种快速而肮脏的解决方案,您可以将“复选框”对象创建为包含Lead实例的不同对象。
public GridLead {
public bool Import { get; set; }
public Lead Lead { get; set; }
}
通过这种方式,您可以轻松地向此对象添加更多“网格”属性,同时始终保留对Lead详细信息的引用,而无需将硬编码属性克隆到其中。
如果你的Lead类有一个拷贝构造函数(例如“Lead(Lead otherLead)”),那么LeadWithImportCheckbox会继承它,你可以在LeadWithImportCheckbox构造函数中调用基础Lead构造函数 - 因此LeadWithImportCheckbox不需要知道Lead的细节。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.