C# 中的向下转型

发布于 2024-07-27 00:28:26 字数 1346 浏览 5 评论 0原文

我遇到了一个不知道如何解决的问题,希望社区能够提供帮助。

我正在编写一个管理“Lead”对象的应用程序。 (这些是销售线索。)我的程序的一部分将从文本文件导入线索。 现在,文本文件包含许多潜在的线索,其中一些我想要导入,另一些我不想导入。

为了便于编程(和使用),我将文本文件解析为 List。 对象,并通过设置 DataGridView 的 DataSource 属性,使用 DataGridView 显示潜在客户。

我想要做的是将一列添加到网格中,称为“导入”,其中包含一个复选框,用户可以选中该复选框以指示是否应导入每个潜在客户。

我的第一个想法是从 Lead 派生一个类: <代码>

public Class LeadWithImportCheckbox : Lead
{
   bool bImport = false;

公共布尔导入 { 获取{返回bImport;} 设置 { bImport = 值;} } }

但是,解析引擎会返回 Lead 对象的列表。 我无法将潜在客户向下转换为 LeadWithImportCheckbox。 这失败了: <代码>

LeadWithImportCheckbox newLead = (LeadWithImportCheckbox)LeadFromParsingEngine;
This is an invalid cast.

我看到的另一个选项是为 LeadWithImportCheckbox 创建一个构造函数:

public LeadWithImportCheckbox(Lead newlead)
{
  base.Property1 = newlead.Property1;
  base.Property2 = newlead.Property2;
  ....
  base.Property_n = newlead.Property_n;
}
This is problematic for two reasons. One, the Lead object has several dozen properties and writing this constructor is a PITA.

但更糟糕的是,如果我更改了 Lead 的底层结构,我需要记住返回并更改 LeadWithImportCheckbox 的构造函数。 这对我的代码维护来说是一个危险。

有更好的方法来实现我的目标吗?

I'm facing a problem that I don't know how to solve and am hoping the community can help.

I'm writing an app that manages "Lead" objects. (These are sales leads.) One part of my program will import leads from a text file. Now, the text file contains lots of potential leads, some of which I will want to import and some of which I won't.

For ease of programming (and use), I'm parsing the text file into a List<Lead> object, and using a DataGridView to display the leads by setting the DataSource property of the DataGridView.

What I want to do is add a column to the grid, called "Import," with a checkbox that the user can check to indicate whether or not each lead should be imported.

My first thought is to derive a class from Lead:

public Class LeadWithImportCheckbox : Lead
{
   bool bImport = false;

public bool Import { get { return bImport;} set { bImport = value;} } }

However, the parsing engine returns a list of Lead objects. I can't downcast a Lead to a LeadWithImportCheckbox. This fails:

LeadWithImportCheckbox newLead = (LeadWithImportCheckbox)LeadFromParsingEngine;


This is an invalid cast.

The other option I see is to create a constructor for LeadWithImportCheckbox:

public LeadWithImportCheckbox(Lead newlead)
{
  base.Property1 = newlead.Property1;
  base.Property2 = newlead.Property2;
  ....
  base.Property_n = newlead.Property_n;
}


This is problematic for two reasons. One, the Lead object has several dozen properties and writing this constructor is a PITA.

But worse, if I ever change the underlying structure of Lead, I need to remember to go back and change this constructor for LeadWithImportCheckbox. This is a danger to my code maintenance.

Is there a better way of accomplishing my goal?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

玉环 2024-08-03 00:28:27

有很多方法可以做到这一点,但由于你所说的,“正确”的方法在这里出现:

为了便于编程(和使用),我
将文本文件解析为
列表对象,并使用
DataGridView 显示潜在客户
设置 DataSource 属性
DataGridView。

我想要做的是添加一列
网格,称为“导入”,带有
用户可以选中的复选框
表明每条线索是否
应该导入。

您的 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; }  
    }
}

当您想要向列表中添加更多元数据(例如,如果您想每周向自己发送有关元数据的电子邮件提醒)时,这将很好地扩展。

There are many ways to do this, but the "right" way pops out because of what you said, here:

For ease of programming (and use), I'm
parsing the text file into a
List object, and using a
DataGridView to display the leads by
setting the DataSource property of the
DataGridView.

What I want to do is add a column to
the grid, called "Import," with a
checkbox that the user can check to
indicate whether or not each lead
should be imported.

Your Lead object stands well on its own, and you want to attach some metadata to it -- you don't want to create another Lead classification (i.e. the LeadWithImportCheckbox class).

So, the best approach in your case is to have a class like so:

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; }  
    }
}

This will scale well when you want to add more metadata to your list, like if you want to send yourself email reminders about them every week.

把回忆走一遍 2024-08-03 00:28:27

我已经多次看到列出的正确解决方案,我感觉就像是再次发布它一样,但解决此问题的最佳方法是为包含导入标志的 Lead 对象编写一个包装器。

如果 Lead 对象的属性没有出现在 GridView 中,因为您正在将数据绑定到该对象,则编写反映包装器对象上的 Lead 属性的直通属性。

问题是您想要向用户显示的内容不是数据模型的固有部分。 答案是在将数据呈现给用户之前对其进行包装,以便您可以控制他们所看到的内容,而无需更改底层模型。

如果您担心 Lead 对象将来会更改多次,以至于更改包装器会很麻烦,您可以研究基于 Lead 对象的动态代码生成,该对象将自动生成具有与以下字段相同的字段的包装器对象: Lead 对象加上导入标志。 但坦率地说,这比您完成这样简单的事情可能需要的工作要多得多。

I've seen the correct solution listed so many times I feel like a heel posting it again, but the best way to approach this is to write a wrapper for the Lead object that includes the import flag.

If the properties of the Lead object don't appear in the GridView because you're databinding to the object, then write passthrough properties that mirror the Lead properties on the wrapper object.

The issue is that you want something displayed to the user that isn't an inherent part of the data model. The answer is to wrap the data before presenting it to the user so you can control what they see without changing the underlying model.

If you're concerned that the Lead object will change so many times in the future that changes to the wrapper will be cumbersome, you could look into dynamic code generation based on the Lead object that will automatically generate a wrapper object with the same fields as the Lead object plus the import flag. Though frankly, that's a lot more work than you'll probably need for something as straightforward as this.

花桑 2024-08-03 00:28:27

作为一种快速而肮脏的解决方案,您可以将“复选框”对象创建为包含 Lead 实例的不同对象。

public GridLead {
   public bool Import { get; set; }
   public Lead Lead { get; set; }
}

通过这种方式,您可以轻松地向该对象添加更多“网格”属性,同时仍然始终保留对潜在客户详细信息的引用,而无需将属性克隆硬编码到其中。

As a quick and dirty solution, you can create your 'checkbox' object as a different object that contains an instance of Lead.

public GridLead {
   public bool Import { get; set; }
   public Lead Lead { get; set; }
}

This way you can easily add more 'grid' properties to this object, while still always retaining a reference to the Lead details without hardcoding property cloning into it.

Hello爱情风 2024-08-03 00:28:27

建议您尝试修改(升级)导入的引导对象。

尝试从此处的示例开始...

Recommend you try modifying (upgrading) your imported lead objects.

Try starting with the examples here...

疯到世界奔溃 2024-08-03 00:28:27

如果您的 Lead 类有一个复制构造函数(例如“Lead(Lead otherLead)”),LeadWithImportCheckbox 将继承该构造函数,并且您只需在 LeadWithImportCheckbox 构造函数中调用基本 Lead 构造函数 - 因此 LeadWithImportCheckbox 无需了解 Lead 的详细信息。

If your Lead class had a copy constructor (e.g. "Lead(Lead otherLead)"), LeadWithImportCheckbox would inherit that and you could just call the base Lead constructor in the LeadWithImportCheckbox constructor - hence no need for LeadWithImportCheckbox to be aware of the details of Lead.

财迷小姐 2024-08-03 00:28:26

或者,为了避免 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);
    }
}

or, to avoid the PITA aspect, use reflection... (try this...)

EDIT: use property, not Field as I had originally written...

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);
    }
}
东北女汉子 2024-08-03 00:28:26
public class LeadListItem
{
    public Lead Lead { get; set; }
    public bool ShouldImport { get; set; }
}

即不复制 Lead 对象的内容,只需将对其的引用存储在新的 LeadListItem 对象中,这会在原始对象“外部”添加额外信息。

如果您希望 Lead 的属性出现在网格中,几乎肯定有一种方法可以做到这一点。 为什么不问这个问题,而不是因为我告诉你这个问题的正确答案而对我投反对票!

public class LeadListItem
{
    public Lead Lead { get; set; }
    public bool ShouldImport { get; set; }
}

i.e. don't copy the Lead object's contents, just store a reference to it in a new LeadListItem object, which adds extra info "outside" the original object.

If you want the properties of Lead to appear in the grid, there is almost certainly a way of doing that. Why not ask that question, instead of downvoting me for telling you the right answer to this question!

青衫负雪 2024-08-03 00:28:26

您可能错过了几个选项:

  • 您可以更新 Lead 对象本身以具有 Import 属性(默认为 false)。
  • 您可以让“ImportLead”对象将 Lead 视为有效负载(如果需要,甚至可以将其设为通用),因此您不需要大型构造函数。
  • 构建一个新的 Lead 对象列表或可枚举对象,其中仅包含您首先要导入的对象。

A couple options you might have missed:

  • You could update the Lead object itself to have an Import property (that defaults to false).
  • You could have your "ImportLead" object treat the Lead as payload (even make it generic, if you want), so you don't need the big constructor.
  • Build a new Lead object list or enumerable that only contains the objects you want to import in the first place.
风柔一江水 2024-08-03 00:28:26

如果要向下转换的对象确实是该类型的对象,则只能向下转换。

解决问题的一种更简单的方法是使用 DisplayLead 类,例如:

  public class DisplayLead {
      Lead lead;
      bool bImport;
  }

它还可以帮助您将存储的数据与其在 GUI 中的表示形式分开。

You can only downcast, if the object to be downcast is really an object of that type.

An easier way to solve your problem would be to have a DisplayLead class, such as:

  public class DisplayLead {
      Lead lead;
      bool bImport;
  }

which would also help you separating stored data from their representation in a GUI.

空名 2024-08-03 00:28:26

您想要做的是在网格上显示复选框列,而不让它与您的潜在客户对象完全相关。 您使用标记的列(可能还有原始列表)来构建一组新的列表,这将是您的导入列表。

然后处理您想要对新创建的列表执行的任何操作。

编辑:使用列表时要小心的一件事是,每个类对象实际上只是指向该类的指针,因此如果您使用原始列表并执行以下操作:

List<Lead> Importable = new List<Lead>();

for(int i=0, i++, i<viewGrid.Count)
    if(viewGrid[i].CheckedColumn.Checked)
        Importable.Add(OriginalList[i]);

该对象将存在于两个列表中,并且如果您编辑任一列表中潜在客户的数据都将发生更改。

What you want to do is display the checkbox column on your grid and not have it related at all to your Lead objects. You use the marked columns (and possible the original List) to build a new set of List which will be your import list.

Then handle whatever you wish to do with the newly created List.

Edit: One thing to be careful of when working with lists is the fact every class object is actually only a pointer to the class so if you work with the original list and do something like:

List<Lead> Importable = new List<Lead>();

for(int i=0, i++, i<viewGrid.Count)
    if(viewGrid[i].CheckedColumn.Checked)
        Importable.Add(OriginalList[i]);

That objects will exist in both lists and if you edit data of a Lead on either list both will be changed.

梦醒灬来后我 2024-08-03 00:28:26

我不能沮丧到它不是的东西。 如果该对象被实例化为Lead,则它不能向下转换为任何派生类。 如果它被实例化为 LeadWithImportCheckbox,然后作为 Lead 返回到您的代码,那么您可以向下转换它。

专业提示:使用 is 运算符在运行时检查类型。

I cannot downcast to something it is not. If the object was instantiated as a Lead, then it can't be downcast to any derived class. If it were instantiated as a LeadWithImportCheckbox and then returned to your code as Lead, then you can downcast it.

Protip: Check type at runtime with is operator.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文