简体   繁体   中英

Property Accessors on List<T> in .NET

I have a property called Fruits which contains a comma delimited string in the form "apples,bananases,peaches"

I want to make a list in the same class which makes the Fruits property easier to manipulate. Accessors won't work as they are not supported on lists or so it seems.

Basically i want a property called FruitList which auto populates based on the Fruits Property and when adding items or manipulating the FruitList it should auto populate the fruits property.

I need the Fruits Property for Entity framework.

You can invert the logic:

List<string> fruitsList = new List<string>();
public List<string> FruitsList
{
    get
    {
        return fruitsList;
    }
}

public string Fruits
{
    get
    {
        return string.Join(',', fruitsList);
    }
    set
    {
        // Incomplete, does not handle null
        FruitsList.Clear();
        FruitsList.AddRange(value.Split(','));
    }
}

You don't need to worry about updating Fruits if Fruits is determined by looking at FruitsList . You mention that you need Fruits as a string property for Entity Framework, but EF does not care whether it is backed by a string field.

The only realistic way to do this is to use a collection which can be observed for changes, and handle the event raised when it is changed, and update the property.

Something like ObservableCollection<T> would fit the bill.

example:

public class MyObject
{
    public string Fruits{get;set;}

    public IList<string> FruitList 
    {
        get
        {
            var list = new ObservableCollection<string>(Fruits.Split(','));
            list.CollectionChanged += (s,ea) => {
               var items = (IList<string>)s;
               Fruits = String.Join(",",items);
            };
            return list;
        }
    }
}

Usage:

var obj= new MyObject(){ Fruits="Apple,Banana,Orange" };
var list = obj.FruitList;
list.Add("Satsuma");
list.Add("Grapes");
list.Remove("Apple");
Console.WriteLine(obj.Fruits); // Output: Banana,Orange,Satsuma,Grapes

Live example: http://rextester.com/KCT33825

Having seen the concept here work, it's worth noting that the above implementation is frought with a bit of danger. It creates a new ObservableCollection every time you call the get accessor on it, which could have some unintended consequences.

For example, if you add the following line just before my original Console.WriteLine :

Console.WriteLine("{0}", obj.FruitList == list);

It outputs false which might seem strange as you might (and notionally, should) expect list and obj.FruitList to point to the same list.

You can get round this by changing the implementation to create only ever 1 ObservableCollection and always returning that from the get accessor:

public class MyObject
{
    private string fruits;
    private ObservableCollection<string> fruitList;
    public string Fruits
    {
        get{ return this.fruits; }
        set
        {
            this.fruits = value;
            this.fruitList = CreateFruitList();
        }
    }

    private ObservableCollection<string> CreateFruitList()
    {
        var list = new ObservableCollection<string>(this.fruits.Split(','));
        list.CollectionChanged += (s,ea) => {
           var items = (IList<string>)s;
           this.fruits = String.Join(",",items);
        };
        return list;
    }


    public IList<string> FruitList 
    {
        get
        {

            return fruitList;
        }
    }
}

Now all is right with the world again!

here's what you could do, create a proxy for your comma separated list:

public class MyClass
{
    public string Fruits {get;set;}

    public string [] FruitList {
        get { return Fruits.Split(new [] {','}); }
        //warning, the setter is dangerous
        set { Fruits = string.Join(',', value); }
    }
}

When I say the setter is dangerous, I only mean that if you change one element of the array, the Fruit won't be updated. It'll only be updated if you push a new array. If you need that behavior, consider implementing it using an ObservableCollection

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM