The basic question I have, is: Will the code in the way I write it still efficiently perform when the List "myElements", which I am going to describe in the following, gets larger. In the final program, this List will contain around 2000 or more objects. Here we go:
The task that I have to solve is providing an application that enables the user to search for elements that have certain properties. Up to now, these elements are implemented in the following way:
public abstract class BaseClass
{
public string property1;
public string property2;
//+ lots of more properties (ca. 30) that all derived classes contain
BaseClass()
{
property1 = String.Empty;
property2 = String.Empty;
}
}
public DerivedClass1 : BaseClass
{
public string property3;
//property that only this derived class contatins
DerivedClass(string prop1, string prop2)
{
this.property1 = prop1;
this.property2 = prop2;
property3 = "prop3";
}
}
//+ more derived classes and derivations from them also
Later in the code, instances are created as follows:
DerivedClass myObj1 = new DerivedClass("text1", "text2");
DerivedClass myObj2 = new DerivedClass("text3", "text4");
This is where the list comes in: finally, these objects are added to the list like that:
myElements.Add(myObj1);
myElements.Add(myObj2);
//+ List will contain around 2000 objects
What I know want to do is creating dropdown menus. These menues will appear on a windows form in different columns. The first column will contain comboBoxes that allows the user to choose properties the BaseClass contains. In the above example the choosable options in one of those boxes (which represents the values of property1) would be "text1" and "text3".
Now, depending on the value of this property from the base class, the user will be shown different results in the second column comboBox. Here, we just have one DerivedClass, so there will only be one option in the dropdown: "prop3". Imagine one more DerivedClass that could contain a constructor with the code
DerivedClass(string prop4)
{
prop4 = "text5";
}
I we had an object from this class, the value "text5" should appear in the second column comboBox as well.
Up to know, the population of all comboBoxes is done by foreach loops that goes through all elements of the list "myElements" and adds an item to the comboBox if this item is not already inside the items list of the box. This is done step by step: User clicks a button the first time - first column comboBoxes are populated, user clicks the same button the second time - second column comboBoxes are populated (result depending on values that user has choosen in first column boxes).
My basic question: Every time the user clicks the button, the comboBoxes are filled by using a foreach-loop that goes through ALL elements of the list "myElements". If the list gets bigger, this seems quite a silly solution to me, especially when populating the first column. If there are two classes that derive directly from BaseClass and whose constructors define the value of property1 then the values that the user needs to see in the first column comboBoxes are known at an quite early point of the program.
Can I access these values WITHOUT going through the whole list of elements? Using common sense, I ask myself: if there are TWO derived classes and, therfore, TWO constructors that define property1, there MUST be way of searching that finds these two values not by scrolling through 2000 objects, but by doing somehow only TWO steps.
Does such a way exist? What would be the topics I need to learn to implement it as described?
In addition: Does it make sense to store these 2000 elements in "myElements" in a database rather then in the code itself? Would that still allow the user to "click through" the properties based on the defined class structure? What would be the advantages?
Thanks a lot for any suggestions / literature hints!
I just switched to C# from Java and just became familiar with the notion of Property, which seems to be the common way of getting and setting field values.
So what should I do if I need to update the field values pretty often, but not setting them to totally new values? Like, there is a field in my class that is a List, and I need to sometimes append elements into it, while keeping the rest of the List unchanged. Should I just go ahead and create a method like
void append(Point p) { }
or is there a more elegant or civilized way of doing this in C#?
There is no single "correct" way of setting private fields through an API. The answer depends on what functionality you would like to present to your users.
If you would like to let them access your List<Point> as a read-only collection which they can modify in any way they like, you may present your list as a read-only property:
public IList<Point> Points {get;} = new List<Point>();
If you think that this approach gives your users too much freedom, and you would prefer to have tighter control over the points that appear on the list, you may want to expose a property for accessing the list as IEnumerable<Point> and a bunch of methods for adding / removing / modifying points on the list.
private IList<Point> points = new List<Point>();
public IEnumerable<Point> Points => points;
public void AddPoint(Point p) {
// validate p before inserting on the list,
...
points.Add(p);
}
Note: Code examples above use C# 6 syntax.
If you wanted to allow modification to the list but not allow the instance to be changed you could write
public IList<Point> MyPointList {get; private set;}
However if you wanted to only support adding elements, then the add method would be a good way to go.
C# syntax is simple and elegant and a joy to write with. In a Class you can create a private field that backs up a public getter and setter. From within this Class, you can set or get the private field as you like. If a different Class needed to access the field, it would need to use the public getter and setter. Example: A private List could be created and edited from within the class however you choose to. With a custom add method or using the List .Add method. From a different class you would simply call the public List properties .Add method. There really is just one private List that is being edited. You can create another private List for another task. Maybe a staging area for items waiting to be validated before entering the main list.
I've recently run into a snag in my program where using a list of a user defined class has been corrupting data. Example:
class myClass {
public int x;
}
myList<myClass> = new List<myClass>();
myClass myObject = new myClass();
myList.Add(myObject);
myList.Remove(myObject);
When I try to add something to the list, my data is being corrupted. I believe removing objects is also causing problems, although this could be because they're corrupted in the first place. I've seen similar issues here and there and was hoping someone could explain to me what's going on. While the links do provide me with some answers, they're not doing a good job of explaining what's going on behind the scenes.
EDIT: I should have been more clear before about how my data is being corrupted. The values in the fields of my objects are being changed when they are added to the list. For the purposes of my program, the values should all be 0 or 1 but when added to the list change to -1 to 3.
EDIT 2: The source of the problem was an unfamiliarity with C#. Coming from a C++ background I assumed that objects were passed by value and not by reference. Changing my custom class from a class to a struct resolved the issue instantly. Thanks to #MattW !
There isn't too much to go on here - so the following is a guess at the problem ...
Are you changing the value of myObject after adding it to the List<>? Remember that since you are adding a Class to the list (and all Classes are Reference types), that if you change the value of myObject after adding it to the list, it will be changed everywhere (including inside of your List<>).
For example:
List<myClass> myList = new List<myClass>();
myClass myObject = new myClass();
myObject.x = 5;
myList.Add(myObject);
Console.WriteLine(myList[0].x); //this will be 5
myObject.x = 7;
Console.WriteLine(myList[0].x); //this will be 7
Even though you didn't touch the List<> itself, you changed the value of the Referenced object, so it is changed everywhere it is being Referenced.
Check Out Value vs Reference types
Does anyone know if the following is possible to pass in a List<> of objects to a function and specify which property the function should use within each object that its working with ?
I have a class that works with a specific property of an object throughout the class, but I dont want to create multiple copies of the same class to work with different properties of that object. I thought about using Linq, but I dont see a way to specify which property to use in other functions of the manipulation class.
I was thinking there has to be a more elegant way to do this instead of creating the same class to handle each property. I thought about using Reflection to tell the function which property to work with but that gets ugly really quick
Example psuedo code :
class Store
{
int amount;
int id;
int serial;
}
class AggregationMethods
{
bool Has3Values( List<Store> places /* some other param to specify which property to use*/)
{
// do something with Store.amount or Store.id
}
// other functions to work with Store.amount or Store.id or Store.serial
}
In your case, they're all int values - so you could just retain a Func<Store, int> or pass it into each method. It becomes slightly harder if you need to work over multiple types, but we don't really have enough information to comment further.
It's also not clear whether you would expect two have multiple instances of AggregationMethods (e.g. one for amounts, one for IDs etc) or whether these would really be static methods. If you're using instances, then you could keep the projection as a member variable, and apply it within each method.
It's worth noting that the properties you've given probably don't really make sense to apply the same aggregations - for example, while summing amounts makes sense, it's meaningless to sum IDs.
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?
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);
}
}
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!
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.
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.
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.
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.
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.
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.
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.
Recommend you try modifying (upgrading) your imported lead objects.
Try starting with the examples here...
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.