How to set a Property of a List? - c#

I am not sure, but it seems i can not set a Property of a List?
The code in the (set) section does not get executed, debugger does not stop in the set when placing a break-point.
if a list property is dealt with differently? and if there is a link of some reading on this subject.
class test
{
public test()
{
id = new List<string>();
_id = new List<string>();
}
private List<string> _id;
public List<string> id
{
get { return _id; }
set
{
_id = value;
}
}
}
test t = new test();
t.id.Add("one");

The code in the (set) section does not get executed, debugger does not stop in the set when placing a break-point.
It appears that your question is, "why is the set accessor not called when I do: t.id.Add("one");"
The reason is simply that the set accessor is for the List itself. Your code is not setting t.id to a new List<string>, rather it is calling the .Add method of the object returned from the t.id property.
So the execution would look something like:
The get accessor is called when you do t.id, and it returns the instance of _id
The .Add method of _id is then called, and the string "one" is added to the private backing field _id
Note that in your existing code, the set does get called from the constructor, when you explicitly set the id to a new List.
You've stated that your goal is "to change some other properties when I add an item to id". There are a few ways to do this, but probably the simplest to understand and implement is:
In the get accessor for the list, return a copy of the list. This prevents clients from adding an item directly through the Add method. Also note that there is no need for a set accessor.
Provide a separate AddId method on your class, which is what the clients would have to call to actually add an item. This is where you have the opportunity to do something else when items are added to the list.
For example:
class Test
{
private readonly List<string> id = new List<string>();
// Return a copy of our private list
public List<string> Id => id?.ToList();
public void AddId(string newId)
{
id.Add(newId);
// do something else here when we add a new item
}
}
Note that this might cause some confusion for clients of your class, because they can still do test.Id.Add("invalid item"); and they won't get any error, but it also won't add anything to the private list. If they want to add something to the list, they have to call the AddId method:
t.AddId("one");

Related

C# readonly get accessor

Code:-
(Note:- here I'm using read-only word means that property has only get accessor.)
Class Test
{
public List<string> list {get;}
public string name{get;}
public Test ()
{
list =new List<string>();
}
}
Main()
{
Test test =new Test();
test.list.add("c#"); //no error
test.name="Jhon"; //here I get compilation because property name is read-only
}
If you see above snippet. Test class contain two property which is name and list. In main method I'm creating object of test class to access these properties. So if you see if I try to set value to name property then I'll get compilation error because name property is read only. Similarly if you see another property 'list' that is also read-only if I use add property of List class then without error I'm able to add in list.
So I'm not getting how this happen.
That's because the set would refer to setting the List object, the actual instance of the collection. The List itself, when returned, is not readonly. If you want it to be readonly, you can do something like:
private List<string> list;
public ReadOnlyCollection<string> List {get => list.AsReadOnly()}
You have a misunderstanding of how a "read only" property would work.
If your code looked like this:
Test test = new Test();
test.list.Add("c#"); //no error because you are not 'setting' the object
test.list = new List<string>(); //Error here because you ARE setting the object
Add() is just a method of a List<T>, you are modifying the object not setting the property to something else.
If you want your collection to be "read only" you can use the ReadOnlyCollection interface. You can manage a private list internally and only expose through the public ReadOnlyCollection. Your desired functionality was never made clear so I wouldn't know what to suggest beyond what I have.
This is because in case of a string you return a copy of the instance - you can not assign to it.
Why .NET String is immutable?
In case of a List<T> you return a reference to an instance, which is not constant in your case - it is possible to change it.
To prove that yourself, you can do something like :
class Test
{
private string val;
public ref string Val {get {return ref val;}}
}
void Main()
{
Test t = new Test();
t.Val = "a";
Console.WriteLine("t.Val is - " + t.Val);
}
Observe special ref keyword I used in string property, to denote that string reference has to be returned and not a copy of it.
C# Concepts: Value vs Reference Types (Joseph Albahari)
public List<string> list {get;}
That means, it causes the error if you do the same action with name.
test.list = new List<string>();
test.list to get the list object and you call the method Add of the list object. So it's normal.

List item doesn't update

Well, i have a simple List of classes which might get updated during run-time the problem is that when i set a property it doesn't update in the List.
Code:
class Foo
{
public List<Link> Link => new List<Link>();
public Foo()
{
//... Code that adds items to the list.
var addr = Link.Find(_ => _.Valid).Use().Address;
//here if i break and look at the Link list it must contain an item with Valid = false, yet it doesn't
}
}
public class Link
{
public Uri Address { get; set; }
public bool Valid = true;
public Link Use()
{
Valid = false;
return this;
}
}
i know that it must update because i am using a reference of that item in the list, yet for some unknown reason it doesn't.
Each time you are getting the value of Link property new list instance is created and returned. You should initialize property only once and return the same instance of the list when you are getting property value:
public List<Link> Link { get; } = new List<Link>();
Why your code do not work? Think about what happens when you add two items this way and perform a search:
Link.Add(new Link());
Link.Add(new Link());
Link.Find(...)
You are calling getter of Link property which creates new instance of the list and returns that empty instance.
You are adding first Link object to the instance of the list which you are received in step #1.
You are calling getter of Link property again, which creates new instance of the list (yes, another instance) and returns that new instance (empty list).
You are adding second Link object to the new empty list return on step #3.
You are calling getter of Link property which creates third instance of the list (again, empty) and returns that instance.
You are calling Find method of the empty list returned on step #5.

Sort List<T> Property every time an item is added

I have a List in a class that I have as a property:
public List<string> MyList { get; set; }
Data will be added to this list and eventually the data will be read. When the data is read, it will be read like:
foreach(string str in my_obj.MyList)
{
// do something
}
I could, of course, do:
foreach(string str in my_obj.MyList.Sort())
{
// do something
}
but since this is a class library I do not want the use to have to do anything. I also do not want the user to have to call a Sort() method within the class. What I would ideally have is the list being sorted every time an item is added or when it is read.
You can change your property like this, use a backing field and sort it in the getter method before you return the list to the caller:
private List<string> _myList;
public List<string> MyList
{
get { _myList.Sort(); return _myList; }
set { _myList = value; }
}
Ofcourse this will perform sorting when you attempt to add new item to your list like myobj.MyList.Add("foo"); to avoid this you can add another method e.g. AddToMyList and use _myList.Add instead.And also change the property type IEnumerable<string> to prevent the user from adding new items directly.
Handle adds via an add method in your class. Doesn't protect against direct access of the list but you can insert the item into the correct index of your list based upon your sort requirements.
This approach saves you resorting your list as a single hit.
Just another idea to consider.
You can implement such collection with ObservableCollection Class
Refer URL : http://msdn.microsoft.com/en-us/library/ms668604%28v=vs.110%29.aspx
Assuming there are no duplicates in you list you should use SortedSet It's a set, so it can't contain the same object twice (but how would you sort objects which are the same?), but otherwise it does exactly what you need.
You could also consider implementing IEnumerable in the class which contains the list, that would allow you to simple do foreach(string str in my_obj) You can then make the list private and sort it once after all objects are added. Right now each user which gets the list can also change it, remove items etc. Which may not be what you want.
The implementation can be as simple as this:
public class MyClass : IEnumerable<string>
{
private List<string> myList = new List<string>();
public MyClass()
{
// Fill myList...
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return myList.GetEnumerator();
}
public IEnumerator<string> GetEnumerator()
{
return myList.GetEnumerator();
}
}
You can use System.Linq namespace, after you add using System.Linq then you should be able to do following
List<string> list = new List<string>();
list = list.OrderByDescending(i => i).ToList();
OR if you want to sort ascending order
list = list.OrderBy(i => i).ToList();
If you call those methods after adding item. Your list will be sorted.
Why not to go with SortedList ??
I guess thats exactly what you are looking for. You can just ignore the value of "short" in SortedList or just provide some default value. Or may be you can find some means to utilize field too.

Issue with getters and setters Methods

In my CustomView class, TaskText and ProjectText are comboboxes. See the following property written for getting value from TaskText. My TaskText combobox contains list of Tasks. When I select specific task at runtime, it should store id of that Task which I've done in setters. But I don't understand, how do I get that id?
Later, I'll convert that id to integer and passed to method.
See the below code, which I've tried-
public Harvest_Task taskClass
{
get
{
return new Harvest_Task { _id = Int32.Parse(TaskText.Text) }; // Here _id doesn't take the value.
}
set
{
if (value != null)
{
TaskText.Text = (value._id).ToString();
}
}
}
Usually you create a getter/setter to a specific property of a class and not the whole class itself...
Plus the way you're trying to do things, i recomment trying a Singleton class.

Convert custom Class to List<>

Scenario:
i have a web form from where i m taking input for Item class now i want to assign values to feature that have return type of list how can i do that.
item value = new item(),
value.feature = serialtextbox.text; //error
foreach ( var item in value) //error
{
item.SerialNo= serialtextbox.text;
}
Item and Item feature classes
Class Item
{
list<Itemfeature> features;
}
class ItemFeature
{
public int SerialNo
{
get { return serialno; }
set { serialno = value; }
}
public int Weight
{
get { return weight; }
set { weight = value; }
}
}
Plz help me out
Note: No language is specified, but it looks like C#. I'm assuming C# in this answer.
It's not really clear what you're trying to do here, but I'll give it a shot. First of all, you're going to want to post the actual code you're using. This code won't even compile, it's loaded with syntax errors.
Let's take a look at your objects first:
class Item
{
List<ItemFeature> features;
}
class ItemFeature
{
public int SerialNo
{
get { return serialno; }
set { serialno = value; }
}
public int Weight
{
get { return weight; }
set { weight = value; }
}
}
You have a custom class, ItemFeature, which consists of a serial number (integer) and a weight (integer). You then have another custom class, Item, which consists of a list of ItemFeatures.
Now it looks like you're trying to add a new ItemFeature to the Item and then loop through all of them and set them again?. Something like this, perhaps?:
Item value = new Item();
value.features.Add(new ItemFeature { SerialNo = int.Parse(serialtextbox.Text) } );
foreach (var item in value.features)
{
item.SerialNo = int.Parse(serialtextbox.Text);
}
(Note that this code is probably as free-hand as your code, so I haven't tested it or anything.)
What I've changed here is:
Setting the SerialNo property, rather than trying to set the ItemFeature directly to a value. You need to dig into the object's property to set a value on that property, not just set it to the entire object.
Converting the input (a string) into the property's type (an int).
Looping through the list, not the Item object itself. The Item object contains a list as a property, but the object itself isn't a list. You can loop through the property, not through the parent object.
A few things to ask/note:
What exactly are you trying to do? You have a list of objects, but you're only setting one and then looping through that one to set it again. Why?
You may want to consider more apt class/property names. Things like "Item" can be a bit unclear.
Your Item class has a public variable, features. This is generally frowned upon. It's better to use a property. That way if you ever have to add logic behind it you won't break compatibility outside of the object itself. The ItemFeature class has properties like this, which is good. They can be additionally shortened by using automatic properties if you'd like, just to keep things clean and simple.
Note that my code isn't doing any input checking on the serialtextbox.Text value. It should be. I presented it in a simpler form as an introductory approach to something that will work under ideal conditions. But something like the following would be better:
var serialValue = 0;
if (!int.TryParse(serialtextbox.Text, out serialValue))
{
// Here you would probably present an error to the user stating that the form field failed validation.
// Maybe even throw an exception? Depends on how you handle errors.
// Mainly, exit the logic flow.
return;
}
var value = new Item();
value.features.Add(new ItemFeature { SerialNo = serialValue } );
Edit: I just noticed that my call to .Add() will actually fail. You'll want to initialize the list before trying to use it. Consider changing the Item class to something like this:
class Item
{
public List<ItemFeature> features { get; set; }
public Item()
{
features = new List<ItemFeature>();
}
}
Two things changed here:
I converted the public member to a property, as previously mentioned.
I added a constructor which initializes the list so that it can be used. Otherwise, being a reference type, it would default to null. So any call to .Add() or any other method on the list would throw a NullReferenceException because there's no object on which to call the method(s).

Categories