I have created a derived collection object to introduce some added functionality to filter the active records in the collection as shown in the below code snippet. How to achieve it as i want to just filter the same collection while keeping the original references in the filter without creating copy.
public class ExtendedTypes : List<ExtendedType>
{
public ExtendedTypes Active
{
get { return this.Where(x => x.IsActive).ToList(); } // Compile Error
}
}
Filtering an existing list
You mentioned that you wanted to just filter the existing list without keeping a copy. In this case, creating a List won't do, since creating a list from the subset will always create a new collection, not just a filter. List<T> is not a lazily-evaluated collection.
What you probably need to do is either define Active as IEnumerable<ExtendedType> and return the result of the Where directly (using LINQ's lazy implementation), or, if you're in WPF, use something like CollectionView as an additional filter on top of a collection, like this:
public ICollectionView ActiveTypes
{
get
{
if (_activeTypes == null)
{
_activeTypes = CollectionViewSource.GetDefaultView(myExtendedTypes);
_activeTypes.Filter = (type) => (type as ExtendedType).IsActive;
}
return _activeTypes;
}
}
You can now bind to ActiveTypes and get only a subset of the original list, filtered by the result of the Filter clause.
Creating a new List
However, assuming ExtendedType is a Reference type, you don't have to worry about copies of the items themselves being made by duplicating the list. If you don't mind creating a copy of the list with the same references, use my original answer:
The compiler is correct, in the sense that an ExtendedTypes is-a List<ExtendedType>, but not the other way around, and ToList() create a List<ExtendedType>.
There is, however, a simple workaround. Rather than ToList, just create a new ExtendedTypes with a constructor that initializes from a collection:
public class ExtendedTypes : List<ExtendedType>
{
public ExtendedTypes (IEnumerable<ExtendedType> items) : base(items)
{}
public ExtendedTypes Active
{
get { return new ExtendedTypes(this.Where(x => x.IsActive)); }
}
}
Related
I have a class with a static list as shown below:
public class Context
{
private static readonly List<Definition> definitions;
static Context()
{
definitions = LoadXML("path-to-xml-file.xml"));
}
public static List<Definition> GetDefinitions()
{
return definitions;
}
}
My problem is making calls to GetDefinitions() seems to return the list by reference instead of by value, because when I do this elsewhere in my code:
var defs = Context.GetDefinitions().ToList();
defs.ForEach(a =>
{
a.Name = a.Alias ?? a.Name;
});
all subsequent calls to Context.GetDefinitions() will return the modified list - not the original one, hence my conclusion that defs is not a value but a reference to the definitions list.
I tried adding the .ToList() in an attempt to decouple the reference but still I get the same result.
I am also open to a workaround, which allows me to use .Select() instead of .ForEach() in my sample code.
The problem is that the list does not store the items itself, but rather references to the items. Even if you create a new list (e.g. with ToList()), the referenced items stay the same.
In order to fix this, you need to clone the items in the list so that you have a independent copy of the data. You can implement ICloneable on the items and use return the list like this:
public static List<Definition> GetDefinitions()
{
return definitions.Select(x => (Definition)x.Clone()).ToList();
}
This way you create a new list that contains the cloned items. However, cloning an item is a tedious task if you need to clone a deeply nested class structure. For a flat structure, using MemberwiseClone is an easy way.
I have a large library of code that assumes fields contain a single value of class T. Unfortunately, a new client requires us to have those fields point to List(Of T). I can change the field type, but then all the older code breaks.
In VB I would solve this this way:
Private theList As List(Of T) = new List(Of T)
Public ReadOnly Property Thing() As T
Get
Return theList(0)
End Get
End Property
Public ReadOnly Property Thing(i As Integer) As T
Get
Return theList(i) 'yes, this should throw
End Get
End Property
This relies on VB's ability to have multiple properties with the same name, and the overloading the parenthesis for both parameter passing and indexing. However, C# uses braces for the later, and does not have anything corresponding to a parameterized property. Instead, they have "this[]", and since that name is private you cannot have a "this" with no parameter and another with one (that is true, right?).
But how would I do this in C#? I suspect I can do this with a template, but I'm a bit lost how it would look. I can imagine a List(Of T) subclass with a this[], but then I'm not sure how I would implement the accessors in the other classes so that I still have Thing and Thing[i]. And one caveat, these objects are often used from VBA so it needs to be COM-exportable.
You could add a method to access the property instead if the getter itself.
For example:
class Eg
{
List<T> Test { get; set; }
T GetTest()
{
return Test[0];
}
T GetTest(int index)
{
return Test[index];
}
}
You would then access the property like so (and if wanted you could remove the getter):
Eg eg = new Eg();
T t = eg.GetTest();
or
T t = eg.GetTest(i);
I would Suggest using FirstOrDefault from the Linq library, as List[0] will error on an empty list andd also means that you can't switch to any other datatype that doesn't support index reading
private List<T> items = new List<T>();
public T Item
{
get { return items.FirstOrDefault(); }
}
public List<T> Items
{
get { return items; }
}
however properties don't accept parametrisation except in the form of a this Property
if you used a method for this then that will work eg
public T GetData()
{
get { return items.FirstOrDrfault(); }
}
public T GetData(int index)
{
get { return items[index]; }
}
If you need to make your class provide functionality to a new client, you might need to change your design to have them depend on an Interface, rather than the specific implementation of the class.
That said, if sounds like your new client needs a different class, which might contain a collection of your old class, rather than changing your class to fit the new client.
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.
What I have is basically:
public class Object{
public bool IsObjectValid { set; get; }
}
public class MyThing{
public List<Object> Objects { set; get; }
}
What I want to do:
public class ObjectsFiltered{
public List<Object> ValidObjects{
get{
var list = LFs.Sort<_LF> where (IsObjectValid == true);
return list;
}
}
}
I know there has to be a way to sort out the List, filtering out the bool true/false. I just can't seem to wrap my head around Linq fully. I just can't seem to find a tutorial that screams "AH HA!" about Linq Lambda to me :/
I'd rather just return a subset, only only keep one "object" alive... instead of my current setup of multiple sets of lists. KISS.
Ultimately I will use the bool-toggles to feed TreeViews on my WPF form(s).
Clarification: I think the goal is to have a one list (List Objects) and a couple properties that show a filtered version of Objects. Instead of having Objects, ObjecstValid, ObjectsInvalid, ObjectsSomeOtherRuleSet... each a different List...
I'd like to have One List to rule them all... and have properties that return a variation on the list, as desired.
You can use LINQ:
public IEnumerable<Object> ValidObjects{
get{
return LFs.Where(item => item.IsObjectValid)
.OrderBy(item => item.SomeProperty);
}
}
Unless you need a List<T>, it's better to return an IEnumerable<T>, so that you won't store it all in-memory.
The lambda expression item => item.SomeProperty is an inline function that takes a parameter called item and returns item.SomeProperty. (The parameter and return types are inferred by the compiler)
To filter your objects, you can return simply:
return LFs.Where(x => x.IsObjectValid).ToList();
Note, however, that if you intend to draw on that function frequently, you may see some performance boost by maintaining a pre-filtered list internally.
LFs.Where(x => x.IsObjectValid).ToList().Sort()
To sort useing default compared. Otherwise
LFs.Where(x => x.IsObjectValid).OrderBy(x => x.PropertyToSortBy).ToList();
I'm writing a class to represent a Pivot Collection, the root object recognized by Pivot. A Collection has several attributes, a list of facet categories (each represented by a FacetCategory object) and a list of items (each represented by a PivotItem object). Therefore, an extremely simplified Collection reads:
public class PivotCollection
{
private List<FacetCategory> categories;
private List<PivotItem> items;
// other attributes
}
What I'm unsure of is how to properly grant access to those two lists. Because declaration order of both facet categories and items is visible to the user, I can't use sets, but the class also shouldn't allow duplicate categories or items. Furthermore, I'd like to make the Collection object as easy to use as possible. So my choices are:
Have PivotCollection implement IList<PivotItem> and have accessor methods for FacetCategory: In this case, one would add an item to Collection foo by writing foo.Add(bar). This works, but since a Collection is equally both kinds of list making it only pass as a list for one type (category or item) seems like a subpar solution.
Create nested wrapper classes for List (CategoryList and ItemList). This has the advantage of making a consistent interface but the downside is that these properties would no longer be able to serve as lists (because I need to override the non-virtual Add method I have to implement IList rather than subclass List. Implicit casting wouldn't work because that would return the Add method to its normal behavior.
Also, for reasons I can't figure out, IList is missing an AddRange method...
public class PivotCollection
{
private class CategoryList: IList<FacetCategory>
{
// ...
}
private readonly CategoryList categories = new CategoryList();
private readonly ItemList items = new ItemList();
public CategoryList FacetCategories
{
get { return categories; }
set { categories.Clear(); categories.AddRange(value); }
}
public ItemList Items
{
get { return items; }
set { items.Clear(); items.AddRange(value); }
}
}
Finally, the third option is to combine options one and two, so that PivotCollection implements IList<PivotItem> and has a property FacetCategories.
Question: Which of these three is most appropriate, and why?
The best thing to do here is to create your own collection class that inherits System.Collections.ObjectModel.Collection<T> and overrides InsertItem.