Initialize get-only collection in object initializer from existing collection - c#

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; }
}

Related

Identify derived class and instance in one way

I don't really find a good title for this question but it goes as follows. I find myself in a situation where I want to identify a class and an instance of the class. The solution I have is to use a const value for the class and a property that returns that const value for the instance.
I don't know if there is a better solution. It feels a bit strange that I need two ways to identify and just reuse the value. Is there a better way?
Pseudo code below. In the real application there will be more classes that derive from the base class and the objects list will contain instances of these as well. Deserialization happens at startup, serialization at shutdown after after the list has been altered due to user activity.
static void Main(string[] args)
{
List<Base> objects = new List<Base>();
List<string> serializationIds = new List<string>();
// SerializationIds initialized somehow
foreach (var serializationId in serializationIds)
{
switch(serializationId)
{
// Identify class
case Derived.SerializationIdText:
objects.Add(new Derived());
break;
}
}
// add remove objects
foreach (var item in objects)
{
// Identify instance
string serializationId = item.SerializationId;
// Do something with serializationId;
}
}
public abstract class Base
{
public string SerializationId { get; set; }
}
public class Derived : Base
{
public const string SerializationIdText = "DatabaseExplorer";
public Derived()
{
SerializationId = SerializationIdText;
}
}
Instead of looping twice, why not perform the functions of the second loop withint the first the first?
static void Main(string[] args)
{
List<Base> objects = new List<Base>();
List<string> serializationIds = new List<string>();
// SerializationIds initialized somehow
foreach (var serializationId in serializationIds)
{
switch(serializationId)
{
// Identify class
case Derived.SerializationIdText:
string serializationId = item.SerializationId;
// Do something with serializationId;
break;
}
}
}
You might be able to refactor out the code within the switch statement, too, so you could have something like
static void Main(string[] args)
{
List<Base> objects = new List<Base>();
List<string> serializationIds = new List<string>();
// SerializationIds initialized somehow
foreach (var serializationId in serializationIds)
{
string serializationId = item.SerializationId;
// Do something with serializationId;
}
}

Cannot add item to a list initialized in other class

Friends, I would like to know why following code works for List<int> and not for List<string>. When I initialize list in getter of property then it does not work. If I initialize in constructor it works and also if I create list in the calling class it works.
public class MyClass
{
private List<int> _ints;
private static List<string> _strings;
public MyClass()
{
_ints = new List<int>();
}
public List<int> Ints
{
get
{
return _ints;
}
set
{
_ints = value;
}
}
public List<string> Strings
{
get
{
return _strings ?? new List<string>();
}
}
}
class Program
{
static void Main(string[] args)
{
MyClass mc = new MyClass();
// This works
// mc.Ints = new List<int>();
// This works
mc.Ints.Add(1);
// This does not
mc.Strings.Add("Krishna");
}
}
You aren't initializing the variable on the getter, if the variable is null you create a new list but you don't store the reference to it.
Change your code to this:
public List<string> Strings
{
get
{
if(_strings == null)
_strings = new List<string>();
return _strings;
}
}
This mc.Strings.Add("Krishna"); wont work because you return new List<string> every time you call mc.Strings. To explain it in more details :
MyClass mc = new MyClass(); // create new instance of MyClass and store it in the "mc" variable
mc // Direct call to the instance
.Strings // Direct call to MyClass Strings property
// inside Strings property :
// return _strings ?? new List<string>();
// meaning that if "_strings" member field is null
// return new instance of that property's type
.Add("abc"); // adds "abc" to the "forgotten" instance of List<string>
Simply speaking you're doing the same as you would call :
new List<string>().Add("abc");
To get this fixed you can use one-liner ( which you obviously tried ) like this one :
return _strings ?? ( _strings = new List<string>() );
Or use if statement :
if(_strings == null)
_strings = new List<string>();
return _strings;
Because List<int> initializes on the constructor of your class where as List<string> does not. Try:
public MyClass()
{
_ints = new List<int>();
_strings=new List<string>();
}
Your '_strings' list always null. If you call 'get' of 'Strings' property, you always create and return new list instance.
get
{
// if '_strings' is null, then create new instance of list
return _strings ?? new List<string>();
}
You need to use this:
get
{
// If '_strings' is null, then create new instance of list and assign new instance to '_strings'
return _strings ?? (_strings = new List<string>());
}
Inline variant of Gusman's answer, using some of the nice features of C# 6.0
public List<string> Strings => _strings ?? (_strings = new List<string>());
An FYI, to completely understand the problem, you could've put a breakpoint on this line:
return _strings ?? new List<string>();
You would've seen _strings is always null and you need to initialize it as answers above tell you so :)

Create default item in a list and return new item

I would like to add a new item at the back of a list, and get the newly created item.
Let's assume that we could do something like this for one moment:
class Temp
{
public string First { get;set;}
public string Second { get;set;}
}
List<string> list = new List<string>();
var newItem = list.Push();
newItem.First="asd";
newItem.Second = "qwe;
this would be easier than
var newItem = new Temp();
newItem.First="asd";
newItem.Second = "qwe;
list.Add(newItem);
especially when I can't use auto-properties.
Is this possible?
Unless you implement your own List type and add the Push method, the only way you can do that is if the T in List can be constructed using a parameterless constructor.
Here's an extension method for that.
This is not recommended, but is an answer to your question.
Something along the lines of this - I did not compile or run this code
public static class ListEx {
public static T Push<T>(this List<T> list) where T: new() {
// Create an instance of T.
var instance = new T();
// Add it to the list.
list.Add(instance);
// Return the new instance.
return instance;
}
}
You can use object initializers:
var list = new List<Temp>();
list.Add(new Temp{ First = "abc", Second = "def" });
Or together with a collection initializer:
var list = new List<Temp> { new Temp{ First = "abc", Second = "def" } };
This turns your four liner into a one liner.
Or with more than one entry:
var list = new List<Temp> {
new Temp{ First = "abc", Second = "def" },
new Temp{ First = "ghi", Second = "jkl" },
new Temp{ First = "mno", Second = "pqr" }
};
And it should of course be a list of Temp instead of a list of string.

Setting property inside method [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 8 years ago.
Is something like the following possible or do you have to return the list and assign it afterwards? I get object reference not set to instance of an object.
public class MyCollection
{
public List<SomeObject> Collection { get; set; }
public List<SomeObject> CreateCollection()
{
// Is there a way to set the Collection property from here???
this.Collection.Add(new SomeObject()
{
// properties
});
}
}
...
MyCollection collection = new MyCollection();
collection.CreateCollection();
Yes, you can use an object initializer:
public List<SomeObject> CreateCollection()
{
// You may want to initialize this.Collection somehere, ie: here
this.Collection = new List<SomeObject>();
this.Collection.Add(new SomeObject
{
// This allows you to initialize the properties
Collection = this.Collection
});
return this.Collection;
}
Note that this will still potentially have an issue - you are never initializing this.Collection in any code you're displaying. You will need to initialize it to a proper collection in your constructor or via some other mechanism.
It is also an odd choice to have a "Create" method that initializes the local variable and returns a List<T>. Typically, you'd do one or the other. A more common approach would be to place this code within the constructor:
public class MyCollection
{
public IList<SomeObject> Collection { get; private set; } // The setter would typically be private, and can be IList<T>!
public MyCollection()
{
this.Collection = new List<SomeObject>();
this.Collection.Add(new SomeObject
{
Collection = this.Collection
});
}
}
You could then use it via:
MyCollection collection = new MyCollection();
var object = collection.Collection.First(); // Get the first element
That being said, in general, there is no real reason to make a custom class for a collection like this in most cases. Just using a List<SomeObject> directly is typically sufficient.
It's completely possible - you just have to instantiate it first, before you can use it:
public List<SomeObject> CreateCollection()
{
this.Collection = new List<SomeObject>(); // this creates a new list - the default if you just define a list but don't create it is for it to remain null
this.Collection.Add(new SomeObject()
{
// whatever
});
}
Of course, as pointed out in a comment, if you want that function to return a list, it would have to actually return the list. Presumably you mean public void CreateCollection(), though, since that was your question, whether you actually had to return a list (answer: no).
You must initialize this.Collection before adding elements into it.
public List<SomeObject> CreateCollection()
{
this.Collection = new List<SomeObject>();
this.Collection.Add(new SomeObject()
{
// properties
});
}
You can use a list initializer in this case:
public class Person
{
public string Name { get; set; }
public string Firstname { get; set; }
}
class Program
{
public static List<Person> Collection { get; set; }
public static List<Person> CreateCollection()
{
return new List<Person>()
{
new Person() { Name = "Demo", Firstname = "Demo1"},
new Person() { Name = "Demo", Firstname = "Demo1"},
};
}
static void Main(string[] args)
{
Collection = CreateCollection();
}
}

Change the reference of an instance in List

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"
}

Categories

Resources