Unable to update the contents of a Generic List - c#

I have a simple class which has boolean field:
public struct Foo { bool isAvailable; }
Now I have a List of foos:
List < Foo > list = new List< Foo >();
Later on I enumerate each foo in the list and try to update its isAvailable field:
foreach(Foo foo in list) {
foo.isAvailable = true;
}
But the above code never updates the list. What am I doing wrong here and what's its remedy.

It's because Foo is a mutable struct.
When you fetch the value from the list, it's making a copy - because that's how value types behave. You're changing the copy, leaving the original value unchanged.
Suggestions:
You probably should be using a class
Don't create mutable structs. They behave in ways which can be hard to predict, or at least not the way you might expect when you're not explicitly thinking about it.
While you could change your code to iterate over the list in a different way and replace the value each time, it's generally a bad idea to do so. Just use a class... or project your list to a new list with the appropriate values.
Original answer, when Foo was a class
It should work fine. For example, here's a short but complete program which does work:
using System.Collections.Generic;
public class Foo
{
public bool IsAvailable { get; set; }
public string Name { get; set; }
public override string ToString()
{
return Name + ": " + IsAvailable;
}
}
class Test
{
static void Main()
{
List<Foo> list = new List<Foo>()
{
new Foo { Name = "First", IsAvailable = true },
new Foo { Name = "Second", IsAvailable = false },
new Foo { Name = "Third", IsAvailable = false },
};
Console.WriteLine("Before:");
list.ForEach(Console.WriteLine);
Console.WriteLine();
foreach (Foo foo in list)
{
foo.IsAvailable = true;
}
Console.WriteLine("After:");
list.ForEach(Console.WriteLine);
}
}
Try to adapt your current code to a similar short but complete program which doesn't work, post that, and we can work out what's going on.

You're using a struct as Foo, not a class. Structs are copied, not referenced, and therefore you only modify the copy and not the object stored in the list.
So you basically have two options:
Make it a class
Re-assign the result to the list. To do so, I'd iterate using an index instead of using foreach.

When you fill list, you need to create new istance for each Foo Class.
List list = new List();
Foo foo = new Foo();
foo.isAvailable = false;
list.Add(foo);
foo = new Foo();
list.Add(foo);
foo = new Foo();
list.Add(foo);
if you fill on this way:
List list = new List();
Foo foo = new Foo();
list.Add(foo);
list.Add(foo);
list.Add(foo);
you are reference on same memory location on stack for each object.

Related

C# object initializer will initialize read only properties, but for non-primitive types only

In the following test code I do not understand why the first line of TestMethod is legal, but the remaining two lines are not:
public class Bar
{
public string Prop { get; set; }
}
public class Foo
{
public int Primitive { get; } = 0;
public Func<int, int> Function { get; } = (i) => i;
public Bar Bar { get; } = new Bar();
}
public class TestClass
{
public void TestMethod()
{
var baz = new Foo { Bar = { Prop = "Hello World!" } }; // legal
var buzz = new Foo { Primitive = 1 }; // Property or indexer 'Foo.Primitive' cannot be assigned to -- it is read only
var fuzz = new Foo { Function = (i) => 2 }; // Property or indexer 'Foo.Function' cannot be assigned to -- it is read only
}
}
If it is legal to assign to class-type read only properties like Bar in an object initializer (which it is; and which makes sense, since 'read only' really means 'read only except at class construction time' in C# as I understand it) then why is it illegal to assign to properties with types like like int and Func<int, int>?
This seems even more confusing since (again, as I understand it) Func<int, int> is a reference type, like the Bar property but unlike the int property.
var baz = new Foo { Bar = { Prop = "Hello World!" } }; // legal
This is not an assignment to Bar. It is essentially:
var tmp = new Foo();
tmp.Bar.Prop = "Hello World!";
var baz = tmp;
At no point is .Bar assigned to.
Conversely, however:
var buzz = new Foo { Primitive = 1 };
is:
var tmp = new Foo();
tmp.Primitive = 1;
var buzz = tmp;
which does assign to .Primitive.
If it is legal to assign to class-type read only properties like Bar in an object initializer (which it is [...])
No, it isn't. Object initializers call the constructor and then assign to properties. For example, this code:
var buzz = new Foo { Primitive = 1 };
is just syntactic sugar for this:
var buzz = new Foo();
buzz.Primitive = 1;
That's not valid if Primitive is a read-only property.
(To be very pedantic, it's more generally appropriate to regard it as assigning to a temporary local variable, setting the properties, and then assigning to buzz at the very end, but we'll ignore that for now.)
The code that you've observed working isn't setting those read-only properties - it's getting them, and then setting values using the returned reference. So this:
var baz = new Foo { Bar = { Prop = "Hello World!" } }
is actually equivalent to:
var baz = new Foo();
baz.Bar.Prop "Hello World!";
That's entirely valid, even though Bar is read-only.

Reference variable to an instance member

I have this data class:
class MyClass
{
Foo Foo1 { get; set; }
Foo Foo2 { get; set; }
Foo Foo3 { get; set; }
Foo Foo4 { get; set; }
}
Now, somewhere else in my program, I have this function:
void ModifyMyClass(MyClass myClassInstance)
{
var rightFooToModify = myclassInstance.Foo1;
rightFooToModify = new Foo(); // Here, my intention is to
// modify MyClass, not just the
// local variable 'rightFooToModify'
}
I need to be able to choose one of Foo1, Foo2, Foo3, Foo4 (depending on some conditions) and then set it to a new Foo object.
What would be the best way to achieve this? Are there some kind of reference variable that I can use for this in C#?
EDIT:
I could use (and it is actually what I use right now):
myClassInstance.Foo1 = new Foo();
But, ModifyMyClass() is actually a bit more complicated, for example:
void ModifyMyClass(MyClass myClassInstance)
{
if (someCondition)
{
var rightFooToModify = myClassInstance.Foo1
// ... Do some computation with rightFooToModify
myClassInstance.Foo1 = new Foo(/* some parameters */);
}
else if (someOtherCondition)
{
// The exact same code as the if above , but with
// myClassInstance.Foo2 instance.
}
}
I would like to avoid duplicating the code in the if block in all the following else if. That is why I would like to just use var rightFooToModify = myClassInstance.Foo1 at the start of the method and not duplicate the code needlessly in mutliple ifs.
You can think of it like this
When you assign your property to a local variable,
var rightFooToModify = myclassInstance.Foo1;
all you are doing is writing a post-it-Note with the location of some memory on.
If someone gives you another post-it-note with some more, replacing the original one
rightFooToModify = new Foo();
It doesn't change the original memory, its still there, nothing happened.
This is how pointers/references work. They point/reference a location in memory, you can copy a reference yet overwriting that reference doesn't do anything to the original memory location, you just have a new post-it-note pointing to somewhere else.
However, now for a really contrived example of a way to overcome this with ref return and ref Local
Disclaimer, i don't really advocate doing this in your situation, however for sheer academic purposes lets look at this language
feature
Given
public class MyClass
{
private Foo _foo1;
public Foo Foo1
{
get => _foo1;
set => _foo1 = value;
}
public ref Foo ModifyMyClass()
{
return ref _foo1;
}
}
Example
// create class
var someClass = new MyClass();
// create some memory for it
someClass.Foo1 = new Foo();
someClass.Foo1.SomeValue = "test";
// copy the reference to it
var copy = someClass.Foo1;
// overwrite it
copy = new Foo();
copy.SomeValue = "test2";
// oh nossssssssss!!!! is didn't change!!
Console.WriteLine(someClass.Foo1.SomeValue);
//enter ref local
ref var actualLocation = ref someClass.ModifyMyClass();
// create some memory
actualLocation = new Foo();
actualLocation.SomeValue = "test3";
// omg it worked!!!!
Console.WriteLine(someClass.Foo1.SomeValue);
Output
test
test3
And yet another bizarre and weird usage of ref
someClass.ModifyMyClass() = new Foo();
someClass.ModifyMyClass().SomeValue = "I hope i never see this in my code base";
Console.WriteLine(someClass.Foo1.SomeValue);
I don't know if this will be of any help, but you can have a method returning the correct setter of type Action<MyClass, Foo> , i.e.
Action<MyClass, Foo> GetFooSetter()
{
if (someCondition)
{
return (myClass, foo) => myClass.Foo1 = foo;
}
else if (someOtherCondition)
{
return (myClass, foo) => myClass.Foo2 = foo;
}
}
and then call it like this:
GetFooSetter()(myClassInstance, new Foo());
The use case is not so clear, so I will suggest two options:
If Foo is not immutable, then just modify it's values instead of assigning it to a new instance. You can even add a copy function to copy values from another Foo:
Foo fooToChange = myClassInstance.Foo1;
fooToChange.CopyFrom(new Foo());
Refactor to hold the Foos in an array, then you can ask for it and assign with an index:
class MyClass
{
public Foo[] Foos = new Foo[4];
}
int fooToChange = 3;
myClassInstance.Foos[3] = new Foo();

NullReferenceException with object initializer suggested by resharper

I have a strange issue with the object initializer syntax.
Here are my sample classes:
public class Foo
{
public Bah BahProp { get; set; }
}
public class Bah
{
public int Id { get; set; }
}
Consider following three ways to initialize an object:
The old, verbose but explicit way, working correctly:
var foo1 = new Foo();
foo1.BahProp = new Bah();
foo1.BahProp.Id = 1;
// correctly initialized
The second way i'm always using, using object initializer syntax:
var foo2 = new Foo
{
BahProp = new Bah { Id = 1 }
}; // correctly initialized
A third way resharper has suggested my collegue with a different resharper version(is it a bug?):
var foo3 = new Foo
{
BahProp = { Id = 1 }
}; // NullReferenceException
What is the last approach doing differently?
My resharper version is 2016.1.1, my colleague was on 10.02. My resharper suggested the second way. But what does the third way do and when is it useful?
Update: So it seems that it was a bad resharper sugestion to use the last way, that's why they have changed it meanwhile to use the second way.
You can avoid the NullReferenceException if you want to use the third way by initializing all properties/fields that are reference types inline or in the constructor.
I will definitely not use this strange property assignment syntax.
new Foo { BahProp = { Id = 1 } }
compiles to:
new Foo().BahProp.Id = 1;
or, little more verbose:
var foo3 = new Foo();
foo3.BahProp.Id = 1;
So BahProp is null. You're not constructing it.
(This is perhaps the most confusing syntax in all of C#)
Option 2 works because you're calling the constructor of Bah.
Option 3 would also work if you initialize BahProp inside the constructor of Foo. It will have been constructed by the time BahProp = { Id = 1 } is called.
The same is seen with collection initializers:
public class Foo {
public List<int> Numbers { get; set; }
}
var foo = new Foo { Numbers = { 1, 2, 3 } };
This does not initialize the List. It only calls Add on it.
You really must see new MyObject() { X = 1, Y = 2 } as two distinct parts:
new MyObject() constructs a new object and
{ X = 1, Y = 2 } sets the values of its properties (and that's all it does).
Object and collection initializers can be nested. The top-level initializer must follow a constructor, but a nested initializer does not.

Why my method changes the original value of the object that is passed to it?

I have the following object
var filters = new List<IReportFilter>
{
new ReportFilter
{
ReportColumn = new ReportColumn{ ColumnKey = "Result.IsCompleted"},
Value = "1",
SubFilters = new List<IReportFilter>
{
new ReportFilter { SqlOperator = FilterOperator.Or, ReportColumn = new ReportColumn{ ColumnKey = "User.LastName"}, Value = "Alhayek"},
new ReportFilter { SqlOperator = FilterOperator.Or, ReportColumn = new ReportColumn{ ColumnKey = "User.LastName"}, Value = "Smith"},
new ReportFilter { SqlOperator = FilterOperator.Or, ReportColumn = new ReportColumn{ AggregateFunction = SqlAggregateFunctions.Count}, Type = FilterType.GreaterThenOrEqualTo ,Value = "0" },
}
},
};
The obove object is passed to another class using a method like so
IReportModel ReportModel = Template.CreateReport();
ReportModel.Get(filters);
Inside the the Get method of the ReportModel class I want to loop through the filters list and create a new list without changing the original list. the new list will become a subset of the original.
From with in my Get method here is what I have done
public SqlCommand Build(List<IReportFilter> filters)
{
var a = CloneFilters(filters);
var b = CloneFilters(filters);
List<IReportFilter> standardFilters = ExtractFiltersByAType(a, true);
List<IReportFilter> aggregateFilter = ExtractFiltersByAType(b, false);
}
But every time I execute the method ExtractFiltersByAType the value of a,b, and filters change to equal the same value of aggregateFilter.
I am NOT expecting for any of the variables to change. But they are for some reason that I don't understand.
Here is my CloneFilters method
private List<IReportFilter> CloneFilters(List<IReportFilter> myFilters)
{
List<IReportFilter> copyOfFilters = new List<IReportFilter>();
foreach (var myFilter in myFilters)
{
copyOfFilters.Add(myFilter);
}
return copyOfFilters;
}
And here is my ExtractFiltersByAType
private List<IReportFilter> ExtractFiltersByAType(List<IReportFilter> filtersSource, bool IsStandard = true)
{
List<IReportFilter> validFilters = new List<IReportFilter>();
foreach (var filterSource in filtersSource)
{
if (filterSource.SubFilters != null && filterSource.SubFilters.Any())
{
filterSource.SubFilters = ExtractFiltersByAType(filterSource.SubFilters, IsStandard); //I think this what could be causing this problem
}
if ((IsStandard && !filterSource.ReportColumn.IsAggregate) || (!IsStandard && filterSource.ReportColumn.IsAggregate))
{
validFilters.Add(filterSource);
}
}
return validFilters;
}
Question
Since I am not using ref to pass the object by reference to the method, why is my function changing the value to original object?
When passing a list of object to method in c#, will the system create a copy or will it passes the object by reference?
How can I solve this problem so that every time I execute ExtractFiltersByAType method, only the copy is changed not the originals?
I am thinking that the line filterSource.SubFilters = ExtractFiltersByAType(filterSource.SubFilters, IsStandard); in the ExtractFiltersByAType is causing the problem but I don't understand why and how.
Without ref
When you pass a reference type as an argument (which includes a list), you pass a copy of the reference to that object. This means you can change your object attributes, but can't change the object itself.
Example:
public class Program
{
static void Main(string[] args)
{
Foo foo = new Foo(1);
Console.WriteLine(foo.Bar);
// This will change foo.Bar
ChangeFoo(foo, 5);
Console.WriteLine(foo.Bar);
// Does not change foo
DoesNotChangeFoo(foo, 10);
Console.WriteLine(foo.Bar);
Console.Read();
}
static void ChangeFoo(Foo foo, int newValue)
{
// Since it receives a copy of the reference to Foo, it actually changes foo.Bar value
foo.Bar = newValue;
}
static void DoesNotChangeFoo(Foo foo, int newValue)
{
// Since it receives a copy of the reference to foo, it only updates this method's reference, not changing the caller's reference
foo = new Foo(newValue);
}
}
public class Foo
{
public Foo(int bar)
{
Bar = bar;
}
public int Bar { get; set; }
}
With ref
If you wanted to change the caller's object reference, you would need to pass the actual reference used by the calle's, that's when you use the ref keyword.
Example:
public class Program
{
static void Main(string[] args)
{
Foo foo = new Foo(1);
Console.WriteLine(foo.Bar);
// This will change foo's object reference
ChangeFooObjectReference(ref foo, 15);
Console.WriteLine(foo.Bar);
Console.Read();
}
static void ChangeFooObjectReference(ref Foo foo, int newValue)
{
// SInce you are receiving the actual reference used by the caller, you actually change it's own reference
foo = new Foo(newValue);
}
}
public class Foo
{
public Foo(int bar)
{
Bar = bar;
}
public int Bar { get; set; }
}
Your case
As you correcly assumed, the main cause of your problem is this line:
filterSource.SubFilters = ExtractFiltersByAType(filterSource.SubFilters, IsStandard);
This line actually changes this object's SubFilters.
But it's worth noting that you may have some bigger problems in you Clone method.
private List<IReportFilter> CloneFilters(List<IReportFilter> myFilters)
{
List<IReportFilter> copyOfFilters = new List<IReportFilter>();
foreach (var myFilter in myFilters)
{
copyOfFilters.Add(myFilter);
}
return copyOfFilters;
}
This method return's a new List, but the content of that list is exactly the same as the argument's. This means that, if you change any of the object's contained in the object used as an argument, you change it in the new List too.
Here's an example of what's happening.
static void Main(string[] args)
{
List<Foo> foos = new List<Foo>();
foos.Add(new Foo(2));
List<Foo> newFoo = CreateNewFoo(foos);
Console.WriteLine(newFoo.First().Bar);
foos.First().Bar = 5;
// Since we changed the first object of the old list, and it is the same object in the new list, we will get the new result.
Console.WriteLine(newFoo.First().Bar);
Console.Read();
}
static List<Foo> CreateNewFoo(List<Foo> foos)
{
List<Foo> newFoos = new List<Foo>();
foreach(Foo foo in foos)
{
newFoos.Add(foo);
}
return newFoos;
}
I would suggest implementing the ICloneable interface in your IReportFilter interface, and each concrete class implementing IReportFilter.
ICloneable implements a single method Clone(), which returns an object. This method should create a new instance of the same class in which it's implemented, containing a new object identical to the current object. Than you would change your method to:
private List<IReportFilter> CloneFilters(List<IReportFilter> myFilters)
{
List<IReportFilter> copyOfFilters = new List<IReportFilter>();
foreach (var myFilter in myFilters)
{
copyOfFilters.Add(myFilter.Clone() as IReportFilter);
}
return copyOfFilters;
}
As for implementing the ICloneable inteface, refer to this question:
Proper way to implement ICloneable
Edit
As mentioned by user muratgu in the question comments, your CloneFilter method is doing a shallow copy of your list, what you are looking for is a deep copy. That could be implemented with the aforementioned ICloneable interface.
The only thing that ref does is determine whether the method receiving the parameter can modify the variable passed to it. In the case of an object, that means setting the variable to a different object or setting it to null.
But even if you don't use ref, the method you pass the parameter to can can set its properties or call methods which modify the state of that object. That's normal and expected. When you pass an object to another method, it's not just so that the other method can read its properties. You might also want that method to operate on that object in some way that modifies it.
The simplest example is a List<T>. If you pass a List<string> to another method - without using ref - that other method can add items to the list, modify items in the list, clear the list, etc.
The only difference with using ref is that if the method you pass the variable to sets the variable to a different list or sets it to null, it's going to modify the variable in the method that passed the argument.
Most of the time we don't want a method we call to completely replace the variable we pass in. If we wanted a new object we'd write a function that returns an object, not one that replaces the variable we passed in.

How to create a collection of classes that can be iterated over?

I have a series of properties for an object which are themselves a class:
private ClassThing Thing1;
private ClassThing Thing2;
private ClassThing Thing3;
private class ClassThing
{
public string Name;
public int Foos;
}
In some areas I need to be able to access each property specifically, for example:
label1.Text = Thing1.Name;
However, it is also desirable to create a foreach loop to access each one, like this:
string CombinedString;
foreach(ClassThing Thing in SomeCollection)
{
CombinedString += Thing.Name;
}
The end result must be XML serializable. These examples are very basic, but I hope they more easily demonstrate my need.
I tried creating a dictionary of these properties instead, but a dictionary is not XML serializable. I'd like to simply make all of these properties members of a class that itself can be iterated over, but I'm not sure how.
Can anyone point me in the right direction?
I hope this clarifies some things for you, since i am not entirely sure i understand your question.
//many normal classes can be made xml serializable by adding [Serializable] at the top of the class
[Serializable]
private class ClassThing
{
public string Name { get; set; }
public int Foos { get; set; }
}
//here we create the objects so you can access them later individually
ClassThing thing1 = new ClassThing { Name = "name1", Foos = 1 };
ClassThing thing2 = new ClassThing { Name = "name2", Foos = 2 };
ClassThing thing3 = new ClassThing { Name = "name3", Foos = 3 };
//this is an example of putting them in a list so you can iterate through them later.
List<ClassThing> listOfThings = new List<ClassThing>();
listOfThings.Add(thing1);
listOfThings.Add(thing2);
listOfThings.Add(thing3);
//iteration example
string combined = string.Empty;
foreach (ClassThing thing in listOfThings)
{
combined += thing.Name;
}
//you could also have created them directly in the list, if you didnt need to have a reference for them individually, like this:
listOfThings.Add(new ClassThing { Name = "name4", Foos = 4 });
//and more advanced concepts like linq can also help you aggregate your list to make the combined string. the foreach makes the code more readable though. this gives the same result as the foreach above, ignore it if it confuses you :)
string combined = listOfThings.Aggregate(string.Empty, (current, thing) => current + thing.Name);
//Here is an example of how you could serialize the list of ClassThing objects into a file:
using (FileStream fileStream = new FileStream("classthings.xml", FileMode.Create))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<ClassThing>));
xmlSerializer.Serialize(fileStream, listOfThings);
}
To be able to serialize the objects using this method, they cannot contain a constructor, which is why we use the new ClassThing{Name="",Foos=0} way of creating them.
You're looking for an implementation of the IEnumerable interface. See this link for a quick description of how to implement it.
class MyClass
{
private ClassThing Thing1;
private ClassThing Thing2;
private ClassThing Thing3;
internal IEnumerable<ClassThing> GetThings()
{
yield return Thing1;
yield return Thing2;
yield return Thing3;
}
void Test()
{
foreach(var thing in this.GetThings())
{
//use thing
}
}
}
public List<ClassThing> Things = new List<ClassThing>();
Then you can run your foreach over .Things

Categories