I am new to C#, so bear with me. I have a problem in c# where I can't decide on whether I need a class or a struct. I'm creating a List of either the class or struct and adding elements to it. If I use a struct, then I can add an item, alter it, and add it again and the changes will be seen because it is passed by value. The problem is, structs are not mutable so I can't edit any of the elements later. If I use a class, then if I add an item and alter it, all the items in the list get changed. I have to create a new instance of the object each time if I want it to be different. But I have an object that I only want to change one item in, so I have to copy all the other items to the new object?! WHY? Is there a better solution?
This code illustrates my problem:
namespace TestError
{
public partial class Form1 : Form
{
private List<Thing> lst;
private Thing obj;
public Form1()
{
InitializeComponent();
lst = new List<Thing>();
obj = new Thing();
obj.a = "bla";
lst.Add(obj);
//obj = new Thing();
obj.a = "thing";
lst.Add(obj);
foreach (Thing t in lst)
listBox1.Items.Add(t.a);
}
}
class Thing
{
public string a;
//problem is there are many more items here that don't change!
}
}
Why the struct doesn't work:
namespace TestError
{
public partial class Form1 : Form
{
private List<Thing> lst;
private Thing obj;
public Form1()
{
InitializeComponent();
lst = new List<Thing>();
obj = new Thing();
obj.a = "bla";
lst.Add(obj);
lst[0].a = "new"; //error. if i change it to class, it works.
obj.a = "thing";
lst.Add(obj);
foreach (Thing t in lst)
listBox1.Items.Add(t.a);
}
}
struct Thing
{
public string a;
}
}
Class is the way to go. I've never touch the struct type since I left college.
For the Thing class, you stated" there are many more items here that don't change!". Is that mean the values are fixed or the values are based on the initial object. If the values are fixed, you can assigned some default values in the class.
If the values are based on the initial object, I don't see the hassle of passing the variable while adding the object to the list.
The problem is, structs are not mutable so I can't edit any of the elements later.
This is simply not true; don't get me wrong, I think it is a really bad idea to do what you are trying to here, and I think a class with a Clone() method would be the best solution, but the reason you are thinking this is precisely due to value-type semantics. You need to keep in mind that list indexers (the [0]) are methods - and not direct access; consider:
lst[0].a = "new";
what this line would do, if it compiled, is:
fetch a copy of the object out of the list (this is now a completely isolated and separate copy)
change a field on the copy
discard the copy
The compiler knows that this pretty certainly is not what you intended, so it prevents you making a mistake; the usage there would be:
var tmp = lst[0];
tmp.a = "new";
lst[0].a = tmp;
Oddly enough, though - if lst were an array, then that would work - arrays allow for direct in-situ editing:
lst[0].a = "new";
would compile. HOWEVER, PLEASE DON'T DO THIS:
mutable structs are a bad idea and will cause lots of confusion in your code
public fields are also a bad idea
large structs are also a bad idea
Like I say, my advice here would be a class; if you want convenient copy semantics, then add a Clone() method
Related
I have a two class properdata and pprosecnddata both classes having property
I want to access product property from properdata class list object. How is it possible,below is my sample code
pupilc class ProperData
{
public string code{get;set;}
public List<ProSecndData>Secnd{get;set;}
}
public class ProSecndData
{
public string product{get;set;}
}
I am trying to call property like that
class Program
{
static void Main(string[] args)
{
ProperData.Secnd.Product = "Hello";
}
}
you cannot directly access property of Secnd as it is a list
you need to iterate or select the index of the List<Secnd>
you must initialize Secnd first and Secnd should have items in the list
properData.Secnd = new List<ProSecndData>();
so it can be access via
foreach(var second in properData.Secnd)
{
second.product = "hello";
}
//or
for(var i = 0; i < proderData.Secnd.Count(); i++)
{
properData.Secnd[i].product = "hello";
}
//or
var index = //0-length of list;
properData.Secnd[index].product = "hello";
if you want to have items first then add first on your Secnd List
properData.Secnd = new List<ProSecndData>();
properData.Secnd.Add(new ProSecndData{ product = "hello"});
then you now can iterate the list by using methods above
You are trying to access list as a single object, which is not possible.
you need to create single instance of your list class and then you can add string in that single instance.
properData.Secnd = new List<ProSecndData>();
ProSecndData proSecndData = new ProSecndData();
proSecndData.product = "Hello";
properData.Secnd.Add(proSecndData);
Actually I know the answer already, you have not created a constructor to initialise your List.
I'm guessing you get a object null ref error?
Create the constructor to initialise your list and it should be fine.
But in future, please post the error message (not the whole stack, just the actual error) as well as all the code required to repeat the issue. Otherwise you run the risk of getting your question deleted
(It should be deleted anyway because it could be considered a "what is a null ref err?" question).
Also you are accessing an item in a list like the list is that item (should be more like: ProperData.Secnd.elementAt(0).product, please also note the capitalisation of 'product' in the model vs your code.
Having these enums
ReportType, ReportField and ReportDimension with the following specification:
Basically I have three report types and each one is kind of unique, one supports some of the ReportFields and some of the ReportDimensions (doesn't matter which), I would like to create a dictionary that has 3 KeyValuePair items (for every report type) and has tuple as value that looks like this:
private readonly Dictionary<ReportType, (List<ReportField>, List<ReportDimension>)> _reportTypeDimensionMappings;
I wanted to directly instantiate this structure but the way I intend to, gives me build errors:
private readonly Dictionary<ReportType, (List<ReportField>, List<ReportDimension>)> _reportTypeDimensionMappings = new Dictionary<ReportType,
(List<ReportField>, List<ReportDimension>)>
{
{ReportType.Session, new (List<ReportField>, List<ReportDimension>)
{
new List<ReportField>
{
},
new List<ReportDimension>
{
}
}
},
};
Is there an explicit good practice way to instantiate the value of a dictionary that's a Tuple ?
It's already been suggested that you shouldn't be using a Tuple here, and I agree, but to answer your question, the syntax is quite simple:
private readonly Dictionary<ReportType, (List<ReportField>, List<ReportDimension>)> _reportTypeDimensionMappings =
new Dictionary<ReportType, (List<ReportField>, List<ReportDimension>)>
{
{ReportType.Session, (new List<ReportField>(), new List<ReportDimension>()) }
};
It seems like a class would be better suited for what you need. You could create a class called Report that contains your List<ReportField> and List<ReportDimension> properties.
Tuples are useful for when you need a short-lived, relatively-small collection of values or objects to be treated as one thing (i.e. a return from a method), but there's really not much cost to creating a dedicated class for these types of things either. As Daniel A. White pointed out in your comments section, it makes your code harder to read, and given you don't need much of a reason to create a class for any purpose, I'd say any reason is good enough.
You can create a Tuple object by calling Tuple t = Tuple.Create(object1, object2); then you can get the values by t.Item1 for object1 and t.Item2 for object2
I have a class which have a list
public static List<bar> tempList = new List<bar>();
public static Foo foo = new Foo();
public class bar(){
public string name;
public int age;
}
public class Foo(){
public List<bar> lBar = new List<bar>();
}
I have several textbox controls: age1, age2
on textChange on each control a create a new object
/*------------------------------------------------------------------
Following code: I want runtime calculation for a logic i did with age.
also need to create a new object using the inputs
------------------------------------------------------------------*/
age1_textChaned(...){
createObj( );
}
age2_textChaned(...){
createObj( );
}
private void createObj(){
if(tempList.Count != 0)
tempList.Clear();
if(age1.Text != "")
tempList.Add(new bar("name1", Convert.ToInt32(age1.text));
if (age2.Text != "")
tempList.Add(new bar("name2", Convert.ToInt32(age2.text));
}
Then i have a button btn1 which will create the object then clear the content of textbox.
btn1_Click(...){
foo.lBar = tempList;
clearFields(); //here lies the question, once i clear the fields,
//somehow it is still affecting the values in foo.lBar;
}
private void clearFields(){
age1.Text = "";
age2.Text = "";
}
so when i do this
btn2_Click(...){
foreach(bar b in foo.lBar){ //foo.lBar is empty i dont know why
...
}
}
my current solution on btn1_click i have this
foreach(bar b in tempList)
foo.lBar.Add(b); // instead of foo.lBar = tempList
is the foo.lBar = templist causing these changes?
snippet is only a simpler version of an entirely different project.
Objects in C# are passed around by reference unless specified otherwise.
For example, here is the code you are running and how it works behind the scenes :
// create a new location in memory and refer to it using the variable tempList
public static List<bar> tempList = new List<bar>();
// add a new item to the list
tempList.Add(new bar("name1", Convert.ToInt32(age1.text));
// make the variable foo.lBar to also refer to the same spot in memory as tempList
foo.lBar = tempList;
// clear the spot in memory containing the list
tempList.Clear();
That last line affects both the tempList variable and the foo.lBar variable because they both refer to the same location in memory.
The solution to avoid this is to create a new copy of an object in memory so the two variables are pointing to two separate instances in memory, and clearing one does not clear the other.
That is why your current solution works
// add the memory location of each item in tempList to foo.lBar's list
foreach(bar b in tempList)
foo.lBar.Add(b);
Note that if you call tempList.Clear() it will only clear the memory references being stored in tempList, however the actual objects will still exist in memory elsewhere.
Also with this solution if you did something like this :
tempList[0].name = "A changed name";
it would change the name property of the item in the foo.lBar list as well, since they both share the same reference in memory.
As the title states, I want to know the most efficient ways to invoke a lazy loaded object property. Consider the following class definition:
Class MyObject
{
private _stringList = null;
public List<string> StringList
{
set
{
_stringList = value;
}
get
{
if(_stringList == null)
{
_stringList = new List<string>();
//fill the List with strings from some data source
}
return _stringList;
}
}
}
Now I want to pre-load StringList with the most in-expensive operation, what whould that be?
MyObject obj = new MyObject();
obj.StringList.ToString(); //?
obj.StringList.Count(); //?
obj.StringList.Equals(null); //?
What about:
if(obj.StringList == null){}
I don't like this method but it seems like it would be less expensive than calling a method on the property.
I'm looking for an answer specific to List as well as a generic object.
EDIT: I understand that this is considered a micro optimization but that is not the point of the question. I'm not asking if you like what I'm suggesting doing here. I want to know the best way to do this relative to CPU and/or memory usage and some proof that the suggested method is actually better than others.
I also think that tis kind of optimization is not relevant, but i guess the "best" would be
var someVar = obj.StringList;
Just invoke the getter. You may get a warning since you have an unused variable, but you can suppress this warning with a pragma...
But as Sergey already mentioned, in that case it does not make sense to implement lazy load...
I believe comparison with null is the less expensive way. But I would not care of such micro optimization (if you are loading data from file or database, then all these options is nothing comparing to IO operations). Also if you want to pre-load data, then you don't need lazy-loading. Main point of lazy-loading is to defer data loading until you really will need that data.
UPDATE: If you really want to pre-load data for properties, I suggest you to make it in more explicit way. Otherwise other developers will guess why you are comparing properties with null or setting them to local variables which are not used. Create some method in your class which will clearly show your intent:
MyObject obj = new MyObject();
obj.Load(); // or Initialize()
This is classic example of lazy loading. Also note that using setter is defeating purpose of your example because if every client can reset your list then every client must take care of the loading - this is not so good
Class MyObject
{
private List<string> _stringList = null;
public List<string> StringList
{
get
{
if(_stringList == null)
{
_stringList = new List<string>();
//fill the List with strings from some data source
}
return _stringList;
}
}
}
On another note, if you use List.Count > 0, the optimization for this will be Linq List.Any
Say I have a List<Objects>. I want to define the list of objects in one method, and use them in several others.
Here's the ways I've come up with and I'm looking for more or the correct way to do it.
You can define List<Objects> in every method that uses it.
Pros: It works. No chance of getting the wrong variable.
Cons: Code duplication.
You can use a private List<Objects> defined in the class and update it using (ref ListObjects)
Pros: I only have to define it once.
Cons: I feel like it's messy and bad practice.
You can pass List<Objects> as a parameter to the methods that use it.
Pros: Prevents code duplication
Cons: Have to make my populate functions return functions, and add parameters to my other methods. Possible conflicts with Events?
So that's what I've come up with. I'm really not sure which to use or if there's a better way to do this. Thoughts?
EDIT: Including some code as requested.
private List<MedicalPlan> medicalPlansList;
This is the list. It is a list that gets information from a database, here:
private void BindMedicalList()
{
medicalPlansList = new MedicalPlanRepository().RetrieveAll().Where(x => x.Year == year).ToList();
}
Then it's used to find objects in that list, such as
var result =
medicalPlansList.FirstOrDefault(
c => c.CoverageLevels.Any(p => p.Id == id));
This is, in general, how I'd do it. If you always use the same sequence of functions on a list, consider creating a chained function to handle that. You can also directly pass a function call inside one of the other function calls (as long as it returns a list), but that tends to look messy.
public List<int> DoSomethingWithList(List<int> list)
{
//do stuff
return list;
}
public List<int> DoSomethingElseWithList(List<int> list)
{
//do other stuff
return list;
}
public void SomeOtherFunction(string[] args)
{
var list = new List<int>() { 1, 2, 3, 4 }; //create list
list = DoSomethingWithList(list); //change list
list = DoSomethingElseWithList(list); //change list further
}
If you are working with an object that has a List<T> field, I'd do like this:
public class MyBigClass
{
private List<int> myList;
public MyBigClass()
{
//instantiate list in constructor
myList = new List<int>() { 1, 2, 3, 4 };
}
public void PublicListAdder(int val)
{
myList.Add(val);
}
private void PrivateListCleaner()
{
//remove all even numbers, just an example
myList.RemoveAll(x => x % 2 == 0);
}
}
You rarely need to use ref in C#, because it automatically handles pointers for you. You are (usually) not passing around a struct, you are passing around an object reference (which basically is a pointer).
Your #1 and #2 don't really make sense:
If you define a different list in every method that uses it, then you're using a different list each time. This is not sharing the list; this doesn't work. If you mean "call your method that creates the list from each method that uses it" then the same still applies: you're using a different list each time.
You don't need to use ref ListObjects to update a private member; a private member is just accessed by its name. This isn't bad practice; this is standard object-oriented practice.
Passing all required data into a method as parameters makes the method inherently more reusable as it reduces coupling to the class the method belongs to.
In short: #3 is good practice to an extent, as it increases the reusability of code. However, the use of #2 is fundamentally the reason we have Object-Oriented programming: to save you from repeatedly passing parameters into all your methods. This is exactly what private fields are designed for!
In most cases, I would probably go with Anders' answer. Depending on your situation, another way that is worth considering is to write extension methods for List.
namespace ExtensionMethods
{
public static class MyExtensions
{
public static object DoSomething(this List<T> list)
{
//do the something with list
}
}
}
And then you can use it like so:
var list = new List<int>();
list.DoSomething();
In that example, list is passed as the parameter to the extension method.
Usually a List<T> shouldn't belong to the state of an instance and exposed since it's mutable and you may change the state from the outside otherwise -unless your getter is designed to return a readonly list. Unless your design clearly allow such a possibility when it may occur. My reply doesn't really answer to your question is just a suggestion of good object oriented design. As someone already suggested much better than me you may pass a List back and forth each method and directly modify it.