Change the reference of an instance in List - c#

I have a question about assignment.
public class A {}
public class AHolder
{
public A AnInstance;
}
void Change()
{
A anotherInstance=new A();
anotherInstance.aField="bla";
A anotherInstance2=new A();
anotherInstance2.aField="blabla";
List<AHolder> aList= new List<AHolder>();
aList.add(new AHolder(){AnInstance=anotherInstance});
aList.add(new AHolder(){AnInstance=anotherInstance});
aList.add(new AHolder(){AnInstance=anotherInstance});
anotherInstance=anotherInstance2;
}
How can I implement the code that ensures the changes of all AnInstance values in aList, when anotherInstance changed without using loop?
Update:after executing the code lines above ,i'm trying to get "blabla" value from aList[0].AnInstance.aField.Is it possible?

You could do it using a wrapper class instance, instead of referencing directly to the AHolder instance, but think if you really need this extra indirection layer, as it would make your code less readable.
I expect the following sample explains how to do it:
public class MyData { public string Value; }
public class MyRef { public MyData Instance; }
void Change()
{
var dataFoo = new MyData() { Value = "foo" }
var dataBar = new MyData() { Value = "bar" }
var referer = new MyRef() { Instance = dataFoo }
var list= new List<MyRef>();
list.add(referer);
list.add(referer);
list.add(referer);
// for i=0 to 2 -> list[i].Instance.Value = "foo"
referer.Instance = dataBar;
// for i=0 to 2 -> list[i].Instance.Value = "bar"
}

Related

How to make a list property writable in object initializer but read only in other places?

Consider the following code snippet that does not compile.
class Class
{
public double Value { get; set; }
public int Frequency { get; set; }
}
class BoxAndWhisker
{
private readonly List<Class> _classes = new List<Class>();
public BoxAndWhisker()
{
Classes = _classes.AsReadOnly();
}
public IReadOnlyList<Class> Classes { get; }
}
class Program
{
static void Main(string[] args)
{
BoxAndWhisker baw = new BoxAndWhisker
{
Classes =
{
new Class{ Value=1,Frequency=20},
new Class{Value=2,Frequency=10}
}
};
}
}
I want the property Classes to be read only right after baw is instatiated. How to do so? In other words, Classes must be writable in object initializer but read only in other places.
Edit
I prefer object initializer to parameterized constructor.
Why not pass Classes via constructor? E.g.
class BoxAndWhisker {
public BoxAndWhisker(params Class[] items) {
Classes = null != items
? new List<Class>(items).AsReadOnly()
: throw new ArgumentNullException(nameof(items));
}
public IReadOnlyList<Class> Classes { get; }
}
Then
static void Main(string[] args)
{
BoxAndWhisker baw = new BoxAndWhisker(
new Class { Value = 1, Frequency = 20 },
new Class { Value = 2, Frequency = 10 }
);
...
}
Remove the
set;
From the properties within
Class
And make the Class have a Constructor which sets the initial values of the Properties, therefore they cannot be overwrote / changed
The "object initializer" syntax in C# has no semantic difference compared to a property value assignment.
You can read in the docs:
The object initializers syntax allows you to create an instance, and after that it assigns the newly created object, with its assigned properties, to the variable in the assignment.
So this:
var foo = new Bar { Baz = "baz" };
is completely equivalent to:
var temp = new Bar();
temp.Baz = "baz";
var foo = temp;
So you cannot restrict the property assignment the way you want.
The only solution is to use a constructor as proposed in the other answers.
You pass the IList<Class> instance to the BoxAndWhisker constructor and maintain a backing IReadOnlyList<Class> property
class BoxAndWhisker
{
public BoxAndWhisker(IList<Class> classes)
{
if (classes == null)
throw new ArgumentNullException(nameof(classes));
Classes = new ReadOnlyCollection<Class>(classes);
}
public IReadOnlyList<Class> Classes { get; }
}
The usage example
BoxAndWhisker baw = new BoxAndWhisker(new List<Class>
{
new Class {Value = 1, Frequency = 20},
new Class {Value = 2, Frequency = 10}
});

Is there a way to change referenced value so that all references would be updated?

I want to declare local variables, add them to a List and then pass to a method that changes objects that are referenced by that list's elements.
However I need the original variables to reflect those changes, and they do not.
Is that even possible? Thanks a lot
class TestObject
{
public int test;
static TestObject test3 = new TestObject { test = 3 };
static TestObject test4 = new TestObject { test = 4 };
public static void Test()
{
TestObject test1 = new TestObject { test = 1 };
TestObject test2 = new TestObject { test = 2 };
List<TestObject> list = new List<TestObject>() { test1, test2 };
Test2(list); // list[0] = 3 and list[1] = 4, but test1 still = 1 and test2 = 2
}
public static void Test2(List<TestObject> list)
{
list[0] = test3;
list[1] = test4;
}
}
As people pointed out in the comments to the question, you probably don't need to reassign references if they are changed in the list - there may be a better solution for your problem. But if you do know that this is the way to go - that you need to fully replace the objects in the list and have those changes reflected elsewhere, then you can use a simple proxy and pass a list of proxies instead of a list of your objects.
public class Proxy<T>
{
public Proxy(T obj)
{
this.Reference = obj;
}
public T Reference { get; set; }
}
This way you can create a list of proxies:
var test1 = new Proxy<TestObject>(new TestObject { test = 1 });
var test2 = new Proxy<TestObject>(new TestObject { test = 2 });
var list = new List<Proxy<TestObject>>() { test1, test2 };
And later you can reassign the values as you wish:
public static void Test2(List<Proxy<TestObject>> list)
{
list[0].Reference = test3;
list[1].Reference = test4;
}
Now after the method has returned, test1 and test2 will (indirectly) reference the new objects.
Having said that, I'd say that I think it's cumbersome and hacky - I'd rather change the actual objects than references to them (the proxies do just that).

Initialize get-only collection in object initializer from existing collection

I have a class with a get-only collection property. I would like to initialize the collection with the values from an existing collection.
I know that it is possible to initialize the collection using a collection initializer. I could also create the object and then use AddRange on the collection to add the items of the existing collection. This would however create the object with an empty list and add the existing items afterwards.
Is there a way to create the object with the List properly initialized in the first place (without adding a constructor, of course)?
using System.Collections.Generic;
namespace EmptyConsoleApp
{
internal class Program
{
public static void Main(string[] args)
{
// Compiles, but is not what I need
var firstHolder = new Holder()
{
TheList = {"A", "B"}
};
// Compiles, but initializes the list after object creation
var existingList = new List<string>() {"Foo", "Bar"};
var secondHolder = new Holder();
secondHolder.TheList.AddRange(existingList);
// Does not compile
var thirdHolder = new Holder()
{
TheList = {existingList}
};
}
}
internal class Holder
{
public Holder()
{
TheList = new List<string>();
}
public List<string> TheList { get; }
}
}
No. You can't assign this read-only property from a collection initializer. It is read-only after all.
TheList = { "A", "B" } works since it calls Add on TheList (once for each item added), it doesn't create and assign a new instance, which it is not allowed to.
TheList = { existingList } doesn't work since there is a typing issue (TheList = { existingList[0] } does work).
The best option you have it to create a constructor parameter and drop your idea of using collection initializers for something it isn't fit for.
Is there a way to create the object with the List properly initialized in the first place (without adding a constructor, of course)?
No
It's not. That's what a constructor does. If you don't want to do it in the constructor, there is no way to do it.
it is not possible to initialize a read only property from outside of the class itself.
collection initializer is just a simplified syntax version and it does not mean using this syntax you have the same access as if you are in the class constructor
thirdHolder.TheList = existingList; // this is the traditional way
Perhaps you can use factory class pattern like this
internal class Program
{
public static void Main(string[] args)
{
// Compiles, but is not what I need
var firstHolder = new Holder()
{
TheList = { "A", "B" }
};
// Compiles, but initializes the list after object creation
var existingList = new List<string>() { "Foo", "Bar" };
var secondHolder = new Holder();
secondHolder.TheList.AddRange(existingList);
// Does not compile
//var thirdHolder = new Holder()
//{
// TheList = existingList
//};
//thirdHolder.TheList = existingList; // this is the traditional way
var thirdHolder = Holder.HolderFactory(existingList);
}
}
internal class Holder
{
public Holder()
{
TheList = new List<string>();
}
public static Holder HolderFactory(List<string> theList)
{
return new Holder(theList);
}
private Holder(List<string> theList)
{
this.TheList = theList;
}
public List<string> TheList { get; }
}

copying two lists of ObservableCollection types in c#(wpf)

I have the following class in Wpf
public class test
{
public int id;
public string name;
}
As well as two of the list of ObservableCollection types that I've made right
private ObservableCollection<Test> ClassTest;
private ObservableCollection<Test> TempClassTest;
public MainWindow()
{
InitializeComponent();
ClassTest = new ObservableCollection<Test>();
TempClassTest = new ObservableCollection<Test>();
ClassTest.Add(new Test() { id = 1, name = "T1" });
ClassTest.Add(new Test() { id = 2, name = "T2" });
ClassTest.Add(new Test() { id = 3, name = "T3" });
}
The problem is that whenever the test method is changed, it changes in the first variable like the following code:
private void Button_Click(object sender, RoutedEventArgs e)
{
TempClassTest = ClassTest;
TempClassTest[0].id = 1110;
}
Now the value of ClassTest[0] is id=1110
In C# - Read about reference types.
System.Collections.ObjectModel.ObservableCollection is a reference type. Following line of code:
TempClassTest = ClassTest;
Creates a shallow copy (it does not create entirly new member wise list).
The item in the Collection is also a ReferenceType, so you need to Deep Clone the item again.
Do something like:
public class Test: ICloneable
{
public int Id { get; set; }
public string Name { get; set; }
public object Clone()
{
return new Sample { Id = this.Id, Name = this.Name };
}
}
And then,
ObservableCollection<Test> coll1 = new ObservableCollection<Test>();
coll1.Add(new Test{ Id = 1 });
coll1.Add(new Test{ Id = 2 });
coll1.Add(new Test{ Id = 3 });
ObservableCollection<Test> coll2 = new ObservableCollection<Test>();
foreach (var item in coll1)
{
coll2.Add(item.Clone() as Test);
}
coll2[0].Id = 1500;
the first variable object is assigned to second variable. so, the first variable and second variable pointing the same memory address. so, you change any value of first or second it should effect on two variables.
You use clone
Copy Observable Collection

C# nested object properties

Hello I am doing some tests in C# with nesting properties which return objects, but I am getting an object reference exception.
I want to be able to access the arrays in nested Properties, but in the current context I can see that I'm not instancing any new objects inside the properties.
This is where the basic question comes up... Where do I declare a 'new' object instance in the middle of all this? Do I even need to declare and new object reference inside the 'foo' class or 'bar' class?
namespace CustomProperties_TEST
{
class Program
{
public foo[] Blatherskite { get; set; }
static void Main(string[] args)
{
Program myProgram = new Program();
myProgram.Blatherskite[0].CustomProperty1[0].CustomProperty2 = 999999999;
myProgram.Blatherskite[1].CustomProperty1[0].CustomProperty2 = 999999999;
foreach (var item in myProgram.Blatherskite)
{
Console.WriteLine(item.CustomProperty1[0].CustomProperty2);
}
}
}
class foo
{
private bar[] customevariable1;
public bar[] CustomProperty1
{
get { return customevariable1; }
set { customevariable1 = value; }
}
}
class bar
{
private int customintvariable2;
public int CustomProperty2
{
get { return customintvariable2; }
set { customintvariable2 = value; }
}
}
}
You would want to do something like the following, since arrays are initialized to null by default.
static void Main(string[] args)
{
Program myProgram = new Program();
// This is your missing initialization
myProgram.Blatherskite = new foo[2] {
new foo{CustomProperty1 = new bar[2]{new bar{CustomProperty2 = 1},new bar{CustomProperty2 = 2}}}
, new foo{CustomProperty1 = new bar[2]{new bar{CustomProperty2 = 3},new bar{CustomProperty2 = 4}}}};
myProgram.Blatherskite[0].CustomProperty1[0].CustomProperty2 = 999999999;
myProgram.Blatherskite[1].CustomProperty1[0].CustomProperty2 = 999999999;
foreach (var item in myProgram.Blatherskite)
{
Console.WriteLine(item.CustomProperty1[0].CustomProperty2);
}
}
Using arrays means you'll have to set their size. If you would want more flexibility, use a List, and then you can simply add items to it.

Categories

Resources