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
Related
I want to be able to do something like
public string[]|string stringsOrSingleString;
I want to create a variable that can be an array or a non-array of a specific type (a string in the example).
Example usage
I want to be able to do stringsOrSingleString = "bla" or stringsOrSingleString = new string[] { "bla" };
Do I need a custom class to do this? Preferably, I don't want to use a custom class, but if necessary then ok.
I should be able to tell later on if the value assigned was an array or non-array, using typeof or is, or something.
The whole reason for this ordeal is that I have a javascript API(that I didn't create), and I am trying to make a C# api that follows the JS api/syntax as close as possible.
Is this possible?
May be you want something like this?
public class Item<T>
{
public T Value => this.Values.Length > 0 ? this.Values[0] : default(T);
public T[] Values { get; set; }
}
The class has an array of values and a single value. There are some implementations like this, for example, when you select files with OpenFileDialog: you have a list of files (for MultiSelect case) and also a single SelectedFile. My answer is focused with this in mind. If you need another thing, give more information.
UPDATE
You can update previous class in this way:
public class Item<T>
{
public T Value => this.Values.Length > 0 ? this.Values[0] : default(T);
public T[] Values { get; set; }
public T this[int index] => this.Values[index];
public static implicit operator Item<T>(T value)
{
return new Item<T> { Values = new[] { value } };
}
public static implicit operator Item<T>(List<T> values)
{
return new Item<T> { Values = values.ToArray() };
}
public static implicit operator Item<T>(T[] values)
{
return new Item<T> { Values = values };
}
}
Example usage:
Item<string> item = "Item1";
string text = item.Value;
string sameText = item[0];
Item<string> items = new[] { "Item1", "Item2" };
string[] texts = item.Values;
string item1 = item[0];
string item2 = item[1];
You can create an instance using a simple object or an array. You can access to the first value using Value property and to all items using Values. Or use the indexer property to access to any item.
In C# you need to know the type of the variable. It's difficult work in the same form of JavaScript. They are very different languages.
first off - yes, I had a look at this question: Is object creation in getters bad practice?.
I am also not talking about initializing an object in the accessors / mutators, it is about a specific part of the object I want to be returned in a specific way.
My question is more specific; It does not necessarily only apply to C#, however I am currently looking for a solution to implement in my C# project.
I have a class with a dictionary that maps date objects to a decimal value. In one accessor, I want to return a list of all the keys of the dictionary, another accessors returns the values.
What I also want to have is an accessor that gives me the decimal values in a specific format. It would look something like this:
class Class
{
// Some other properties...
// ....
private Dictionary<DateTime, decimal> dict;
public Class(Dictionary<DateTime, decimal> dict)
{
this.dict = dict;
}
private string FormatTheWayIWant(decimal dt)
{
// Format decimal value.
string s = String.Format("{0:F}", dt);
return s;
}
public ReadOnlyCollection<DateTime> DateTimes
{
get { return new ReadOnlyCollection<DateTime>(this.dict.Keys.ToList()); }
}
public ReadOnlyCollection<decimal> Values
{
get { return new ReadOnlyCollection<decimal>(this.dict.Values.ToList()); }
}
public ReadOnlyCollection<string> FormattedStrings
{
get
{
// Format each decimal value they way I want.
List<string> list = new List<string>();
foreach (decimal dt in dict.Keys)
{
list.Add(FormatTheWayIWant(dt));
}
return new ReadOnlyCollection<string>(list);
}
}
}
This way I can make the following calls (which is my goal!):
DateTime dateTime = DateTimes[0];
decimal s = Values[0];
string formattedS = FormattedStrings[0];
The problem with this approach is that I create a new list everytime I invoke the FormattedStrings accessor, even if I only need one of the formatted strings. I know this is not good practice and can introduce unnecessary performance issues...
The alternatives I thought of are:
I could extend the decimal class and implement a custom ToString()-method.
Or overwrite the KeyValuePair<DateTime, decimal> class and use an indexer in my class.
Or I create a method with a parameter for the index and return just the one formatted string.
Or I could have an own list for the accessor, which gets updated in the set-method for my dictionary everytime I update the dictionary.
The question I have is, is there a way to make this work with an accessor instead of a method, creating custom classes or having strange side effects on other objects when assigning a value?
Thank you in advance.
Ofcourse this can be done with an accessor. You just have to create 3 separate classes for each desired element of your processed collection. Those classes should have their own indexers, so you would be able to access the elements as a list. The difference would be, that they compute each element on demand (wchich is called lazy initialization). So it would go like this (example for your FormattedStrings):
class Class
{
// ...
MyFormattedStrings FormattedStrings
{
get {return new MyFormattedStringsIndexer<string>(this.dict.Values.ToList());}
}
}
class MyFormattedStringsIndexer<T>
{
private IList<T> list; // we take only reference, so there is no overhead
public MyFormattedStringsCollection (IList<T> list)
{
this.list = list;
}
// the indexer:
public T this[int i]
{
get
{
// this is where the lazy stuff happens:
// compute the desired element end return it
}
set
{
// ...
}
}
}
Now you can use your Class like this:
string formattedS = FormattedStrings[5];
and each element you access will be computed as you access it. This solution also has the advantage of separating concerns, so should you ever had to implement different logic for one of your 3 accessors it would be just a matter of extending one of the indexers.
You can read more about indexeres here: http://msdn.microsoft.com/en-us/library/6x16t2tx.aspx
This is VB, but you get the idea...
Public Class Something
Public Property Items As Dictionary(Of DateTime, String)
Public Readonly Property FormattedItem(ByVal index As Int32) As String
' add error checking/handling as appropriate
Return Me.Items.Keys(index).ToString("custom format") ' or whatever your formatting function looks like.
End Property
End Class
It looks like a good candidate for a new class
public class MyObject
{
public DateTime Key {get;set;}
public String Name {get;set;}
public String FormattedString {get;}
}
And then it can be used in any container (List<MyObject>, Dictionary<MyObject>, etc).
Your Dates and Strings property getters are returning a new list on each call. Therefore if a caller does the following:
Class myClass = ...
for(i=0; i<myClass.Strings.Count; i++)
{
var s = myClass.Strings[i];
...
}
then each iteration of the loop will create a new list.
I'm not clear on what you're really trying to achieve here. You are wrapping the dictionary's Keys and Values properties in ReadOnlyCollections. This gives you an indexer, which doesn't have much meaning as the order of the Keys in a Dictionary<TKey, TValue> is unspecified.
Coming (at last!) to your question, if you want to do the formatting in a "lazy" manner, you could create a custom class that implements a readonly IList<string>, and wraps your list of keys (IList<DateTime>). Most of the implementation is boilerplate, and your indexer will do the formatting. You could also cache the formatted values so that you only format once if accessed multiple times. Something like:
public class MyFormattingCollection : IList<string>
{
private IList<decimal> _values;
private IList<string> _formattedValues;
public MyFormattingCollection(IList<DateTime> values)
{
_values = values;
_formattedValues = new string[_values.Count];
}
public string this[int index]
{
get
{
var result = _formattedValues[index];
if (result == null)
{
result = FormatTheWayIWant(_values[index]);
_formattedValues[index] = result;
}
return result;
}
set
{
// Throw: it's a readonly collection
}
}
// Boilerplate implementation of readonly IList<string> ...
}
Given the following class:
public class GenClass<T>
{
private List<T> ItemsList {get;set;}
public Predicate<T> SomeCondition {get;set;}
public bool UsePredicate {get;set;}
public List<T> Items
{
get { //CODE Goes here; }
}
}
I need a way for the list to use the SomeConditionPredicate and return only the items than match the condition, but only if the bool UsePredicate is true. I know I can just use LINQ for this, the problem is that everytime I query with LINQ I get a different instance of an IEnumerable, and this needs to be a property, therefore I need to be able to access the same instance of the List from outside the class, because I will be adding and removing items from it, and I cannot do that with the result of a .Where, for example.
I was thinking of a custom IList<T>, but I'm not really sure how to do that.
You have a conceptual problem here. If it is the same instance, how is it supposed to filter by the condition? The reason why LINQ returns a new enumeration on every call is that it runs the query "live", and multiple queries have to be independent.
That said, you probably shouldn't have to rely on the property returning the same reference each time. If you rely on the instance being the same, what do you expect to happen when/if someone changes the predicate?
And how is adding or removing items supposed to work/act on a filtered list? If you add an item that would be filtered out, what happens?
Your question is a little unclear, but let's start with this:
public class GenClass<T>
{
private List<T> ItemsList {get;set;}
public Predicate<T> SomeCondition {get;set;}
public bool UsePredicate {get;set;}
public List<T> Items
{
get { return UsePredicate
? ItemsList.Where(SomeCondition).ToList()
: ItemsList; }
}
}
What about that doesn't work for your use case?
An IEnumerable can only be used to read the collection, but not to make changes to it. If you want to make changes to it, return an enumeration of filtered indexes instead.
public IEnumerable<int> FilteredIndexes
{
get
{
if (UsePredicate) {
return ItemsList
.Select((item, i) => i)
.Where(i => SomeCondition(ItemsList[i]));
}
return ItemsList.Select((item, i) => i);
}
}
Assuming that you have declared this indexer
public T this[int index]
{
get { return ItemsList[index]; }
set { ItemsList[index] = value; }
}
You can now use the collection like this
GenClass<string> stringCollection = new GenClass<string>();
//TODO: Add items
stringCollection.SomeCondition = s => s.StartsWith("A");
stringCollection.UsePredicate = true;
foreach (int index in stringCollection.FilteredIndexes) {
stringCollection[index] = stringCollection[index] + " starts with 'A'";
}
UPDATE
If you do not want to expose the indexes, you could create a class used as item accessor representing your collection items
public class Item<T>
{
private List<T> _items;
private int _index;
public Item(List<T> items, int index)
{
_items = items;
_index = index;
}
public T Value
{
get { return _items[_index]; }
set { _items[_index] = value; }
}
}
In your collection you would declare this property
public IEnumerable<Item<T>> FilteredItems
{
get
{
if (UsePredicate) {
return ItemsList
.Select((item, i) => new Item<T>(ItemsList, i))
.Where(item => SomeCondition(item.Value));
}
return ItemsList.Select((item, i) => new Item<T>(ItemsList, i));
}
}
Now you can use the collection like this
foreach (Item<string> item in stringCollection.FilteredItems) {
item.Value = item.Value + " starts with 'A'";
}
A general note: You can safely turn the private properties into fields. Properties are normally used as an intermediate to publicly expose field values.
Ok I have a class similar to the following...
public class Order
{
private Guid id;
[DataMember]
public Guid ID
{
get { return id; }
set { id = value; }
}
private List<Items> orderItems;
[DataMember]
public List<Items> OrderItems
{
get { return orderItems; }
set { orderItems= value; }
}
}
public class Items
{
private string itemName;
[DataMember]
public string ItemName
{
get { return itemName; }
set { itemName = value; }
}
}
When I reference in my code I have a method that takes in an "Order" list as the parameter.
ACME.Order newOrder = new ACME.Order();
ACME.Items newItems = new ACME.Items();
newOrder.ID = xxx
newItems.ItemName = xxx
SendOrderWithItemsFunction(newOrder)
The above works fine however I don't have an add function for my items so that I can do something like the following
newOrder.Items.Add(newItem);
and
newOrder.Items = newItems
will not work because it says that it can not implicitly convert newOrder.Items to newItems[].
What am Missing?
I think I might be missing something, but newOrder.OrderItems.Add(newItem) should work just fine, according to waht you have in your post.
Just some other nitpick things:
The pluralization of the "Items" class is wierd, if it is only a single Item. This is probably the reason that it looked "ok" to assign a single item to a List property.
You may have cut it out of your post, but every class that is being serialized by WCF must be marked as a "DataContract", not just the members of the class.
When initializing objects like this, I think it makes it a lot cleaer to use Type Initializers:
var NewOrder = new ACME.Order{
ID = xxx,
OrderItems = new List<ACME.Item>
{
new ACME.Item{
ItemName = xxx
}
}
};
What you do have is an add function in your Order.OrderItems property:
newOrder.OrderItems.Add(newItem);
you can even add a whole list of items to your OrderItems:
var someList = new List<Items>();
//populate someList here
newOrder.OrderItems.AddRange(someList);
You should be able to do:
newOrder.OrderItems.Add(newItem);
If your newItems[] is an array, you need to do this:
newOrder.OrderItems.AddRange(newItem.ToList<Items>());
You have declared newItems as an ACME.Items type, but the OrderItems property of your Order class is a List<Items>. Those types are not assignable from one to the other directly. So, an assignment of newOrder.OrderItems = newItems is like trying to sayList<Items> = Items. That isn't possible based on the classes you outlined above. Instead, you will need to add to the list.
When you have a list within a list, and the Add() method is missing, a workaround is to make a new list, add the items, then set the inner list to the new list. Instead of:
outerList.innerList.Add(item)
..use..
var newList = new List<ItemType>();
newList.Add(item);
outerList.innerList = newList;
I am wondering what is the best way to use properties when dealing with collections.
For example I have a class Foo and I want to have a list of that class stored. Which of the following should be used:
private List<Foo> myList;
private List<Foo> myOtherList = new List<Foo>();
now for the property:
public List<Foo> ListOfFoo
{
get
{
return myList;
}
set
{
myList= new List<Foo>(value);
}
}
Or should the set just be to the value?
public List<Foo> ListOfFoo
{
get
{
return myList;
}
set
{
myList= value;
}
}
Choose
private List<Foo> myOtherList = new List<Foo>();
becuse the other just declares a reference (which is set to null), the sample above declares a reference to a list, creates a list and assignes that new list to the reference.
Choose
public List<Foo> ListOfFoo
{
get { return myList; }
set { myList= new List<Foo>(value); }
}
When you want myList to NOT refelect any changes that happen to the list after it is assigned to myList e.g.
List<string> myFirstList = new List<string>();
myFirstList.Add("Hello");
myFirstList.Add("World");
List<string> mySecondList = new List<string>(myFirstList);
// mySecondList now contains Hello & world
myFirstList.Add("Boyo");
// myFrist List now contains Hello, world & Boyo
// mySecondList still contains Hello & world
Choose
public List<Foo> ListOfFoo
{
get { return myList; }
set { myList= value; }
}
When you want both references to point to the same object e.g.
List<string> myFirstList = new List<string>();
myFirstList.Add("Hello");
myFirstList.Add("World");
List<string> mySecondList = myFirstList;
// mySecondList now contains Hello & world
myFirstList.Add("Boyo");
// myFrist List now contains Hello, world & Boyo
// mySecondList "also" contains Hello, world & Boyo
The "also" above is in quotes, because actually, there is only one list, and both my first and my second point to the same list.
Generally you don't want to use properties of a rich type like List<T> (normally one would use Collection<T>), and generally properties of a collection type are read-only - the collection itself can be modified with methods like Clear, Add etc., and this is normally sufficient.
For example:
class Foo
{
Collection<Bar> _bars = new Collection<Bar>();
public Collection<Bar> Bars { get { return _bars; } }
}
This also leaves you open to validate modifications to the collection by implementing a descendant of Collection<T> and overriding the InsertItem, SetItem etc. methods.
It depends.
When the first style is used, you create a copy of the list, which is generally unnecessary. .Net convention is for the setter to assign the reference to the property. This is why I would lean towards the second option.
However, if you are intending for the copy operation to take place, the first option is what you are looking for.
Generally, expose only an Interface (ICollection, IList or similar), and make it readonly:
private IList<Foo> m_list = new List<Foo>();
public IList<Foo> List {get { return m_list; } }
Advantage: You can modify the implementation, e.g. switch from a List to an Observable List. You might need to make the m_list member of the concrete type rather than the interface, e.g. to use additional funcitonality.
With an settable external list, you run into a few problems. However, there are some cases where this is needed:
the data can be created externally, and is potentially large, and changes frequently (e.g. tens of thousands of items)
the external list should be shared between different instances
Why not use the IEnumerator-Interface on the class and if you have to use a setter, use a certain method.
This way you are hiding the actual List-Implementation as well.
class FooBar : IEnumerator
{
private Collection<Foo> col;
public IEnumarator GetEnumerator()
{
return col.GetEnumerator();
}
public void SetList(Collection col)
{
this.col= col; // you can also make this more general and convert the parameter so it fits your listimpl.
}
}
class Clazz
{
private void WhatEver(){
FooBar foobar = new FooBar();
...
foreach(Foo f in foobar)
{...}
}
}