Downcasting in C #

I ran into a problem that I don’t know how to solve, and I hope that the community can help.

I am writing an application that manages Lead objects. (These are ad campaigns.) One part of my program will import entries from a text file. Now the text file contains many potential customers, some of which I want to import, and some of which I will not.

To simplify programming (and use), I parse a text file into a List <Lead> object and use a DataGridView to display potential clients by setting the DataSource DataGridView property.

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 to import each output.

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 mechanism returns a list of Lead objects. I cannot omit Lead to LeadWithImportCheckbox. This fails:

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

Another option I see is creating 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. First, the Lead object has several dozen properties, and writing this constructor is PITA.

But worse, if I ever change the basic structure of Lead, I need to remember to return and change this constructor for LeadWithImportCheckbox. This is dangerous for my code maintenance.

Is there a better way to achieve my goal?

+6
inheritance c # downcasting
source share
11 answers

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

EDIT: use a property, not a field, as I originally wrote ...

 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); } } 
+6
source share
 public class LeadListItem { public Lead Lead { get; set; } public bool ShouldImport { get; set; } } 

i.e. do not copy the contents of the Lead object, just store the link to it in the new LeadListItem object, which adds additional information "outside" the original object.

If you want Lead properties to appear in the grid, there is almost certainly a way to do this. Why not ask this question, instead of knocking me over to tell you the correct answer to this question!

+4
source share

A couple of options you might have missed:

  • You can update the Lead object itself to have the Import property (the default value is false).
  • Perhaps your ImportLead object treats Lead as a payload (even make it general if you want), so you don't need a big constructor.
  • Create a new Lead List or enumerated list that contains only the objects you want to import in the first place.
+3
source share

What you want to do is show the checkbox column in your grid and have nothing to do with your Lead objects. You use the marked columns (and possibly the original list) to create a new List set that will be your import list.

Then process everything you want to do with the newly created list.

Editing: one thing that should be observed when working with lists is that each class object is actually just a pointer to the class, so if you are working with the original list and doing 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]); 

These objects will exist in both lists, and if you edit Lead data in both lists, both will be changed.

+1
source share

You can only downcast if the object that will be downcast is really an object of this type.

An easier way to solve your problem would be to have a DisplayLead class, for example:

  public class DisplayLead { Lead lead; bool bImport; } 

which will also help you separate the stored data from its presentation in the graphical interface.

+1
source share

I cannot distort something that is not there. If an object was created as a Lead , it cannot be downstream for any derived class. If it was created as LeadWithImportCheckbox and then returned to your code as Lead , you can disable it.

Protip: check the type at runtime using the is statement.

+1
source share

There are many ways to do this, but the “right” way will pop up due to what you said here:

For ease of programming (and use), I parse a text file into a List of objects and use a DataGridView to display the setting of the DataSource DataGridView property.

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

Your Lead object stands on its own, and you want to add some metadata to it - you do not want to create another Lead classification (i.e. the LeadWithImportCheckbox class).

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

 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 if you want to add more metadata to your list, for example, if you want to send reminders by email about them every week.

+1
source share

I have seen the correct solution indicated so many times that it seems to me that it is loading 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 are not displayed in the GridView because you are bound to the object, then write forwarding properties that reflect the Lead properties on the wrapper object.

The problem is that you want the user to display something that is not an integral part of the data model. The answer is to wrap the data before presenting it to the user so that you can control what they see without changing the underlying model.

If you are concerned that the Lead object will change so many times in the future that changes to the shell will be cumbersome, you can study the dynamic generation of code based on the Lead object, which will automatically generate the shell object using the same fields as the object Lead, plus the import flag. Although, to be honest, this is a lot more work than you probably need for something as simple as that.

+1
source share

As a quick and dirty solution, you can create your "checkbox" object as another object containing a Lead instance.

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

Thus, you can easily add additional "grid" properties to this object, while preserving always a link to scroll data without cloning the contents of the hard encoding.

0
source share

We recommend that you try to modify (update) the imported master objects.

Try starting with examples here ...

0
source share

If your Lead class had a copy constructor (for example, "Lead (Lead otherLead)"), LeadWithImportCheckbox inherits this, and you could just call the Lead base constructor in the LeadWithImportCheckbox constructor - from here it is not necessary for LeadWithImportCheckbox to know the details of the Lead.

0
source share

All Articles