So I have a
BaseClass
and several child classes that inherit from the baseclass
ChildClass1
ChildClass2
I have ObservableCollections of child classes that need to be sorted in place, I cannot create a new ObservableCollection<ChildClas1>.
So i wrote a function
private void Reorder(ObservableCollection<BaseClass>)
{
//sort the collection in place
}
then i do Reorder(ObservableCollection<ChildClass1>)
the compiler is complaining that it cannot convert
System.Collections.ObjectModel.ObservableCollection<ChildClass1> to ObservableCollection<BaseClass>
I will take the compilers word for it, but how can I achieve this without having to duplicate my reorder function for every single child type?
I will take the compilers word for it
The reason why you cannot pass a collection of one type to substitute for a collection of another type is discussed in many Q&As on SO - for example, here.
how can I achieve this without having to duplicate my reorder function for every single child type?
One approach is to make your Reorder generic on the type of collection element, and add a constraint to the type parameter to specify that objects must derive from your base class:
void Reorder<T>(ObservableCollection<T> collection) where T : BaseClass {
...
}
Related
I've seen a bunch of questions dealing with getting all types from a base type and so on, but that's not quite what I need. For instance, I have and abstract base class:
public abstract class BasePart
{
//whatever
}
And I have a bunch of classes that derive from it. Like...
public class HorizontalPanel : BasePart { //code }
public class VerticalPanel : BasePart { //code }
public class RainBoard : BasePart { //code }
And so on.
I always list them by the base class:
List<BasePart> parts;
And I use typecasting and generics to do whatever I want with them. However, I came to a point where I need to filter this list and I only want the type information available in it. And only once for type. For instance, if my list has three HorizontalPanels and two VerticalPanels, what I want from it is a List<Type> that only contains {HorizontalPanel, VerticalPanel}. I suppose I can mess around with the objects themselves in chained loops to get what I want, but I'm positive that C# has a better way to do it. Anyone?
There is no language feature to help you with this. The simplest way would be to use LINQ, first use Select to get all the types and use Distinct
parts.Select(x => x.GetType()).Distinct();
You can use Object.GetType() to retrieve the type of the object and populate a list.
Afterwards, since you need a list which contains only one instance of each type, you can call Enumerable.Distinct() on the list you populated previously, and Enumerable.ToList() to convert the resulting enumerable to a list.
All in all, the code will be something akin to:
List<Type> types = new List<Types>();
foreach (Base element in MyList){
types.add(element.GetType());
};
List<Type> unique_types = types.Distinct().ToList();
Which will give you the list unique_types filled with exactly one instance of each type present in MyList.
I want to create a List<System.Type> listOfTypesOfGlasses , where Type must implement a specific interface IGlass , so I could load it with Types of glasses.
Is there a way to enforce in compile time this constraint(must implement IGlass) ?
Implement a method/class that hides the list.
class YourClass {
// intentionally incomplete
private List<Type> listOfTypesOfGlasses;
public void AddToList<T>() : where T: IGlass
{
listOfTypesOfGlasses.Add(typeof(T));
}
}
Edit: below is the original answer here assuming that Type meant a placeholder, not System.Type.
All you should need to do is List<IGlass>.
or
You should write your own wrapper class around List<T> that has the constraint.
or
Subclass List<T> and put the generic constraint on it - however this practice is discouraged.
No - typeof(IGlass) and typeof(Glass) are both Type objects - not different classes that can be filtered in a generic constraint. There's no generic restriction that works off of the values stored. If you want to store instances of types that all implement IGlass that's possible, but you can;t filter the actual Type objects that can be stored.
I'm wondering if there is a way to do this inheritance situation in C#:
public class Item
{
public string Name { get; set; }
}
public class ItemExtended : Item
{
public int ExtendedProp { get; set; }
}
And let's say I have a method that returns objects of type Item:
public Item[] GetItems();
How can I make code like this run?
ItemExtended[] itemsExt = GetItems().Cast(i => (ExtendedItem)i).ToArray();
Where the cast wouldn't fail, the Name property value would be preserved and I would have an additional property ExtendedProp that I could access?
Edit (hopefully to clear some confusion)
In this situation the GetItems method would only ever return items of type Item. I was wondering if there was a casting method that could convert a base type to an inherited type such that all base member values are conserved (without the use of cloning).
If the runtime type of your object is Item, you can not cast it to an ItemExtended -- not unless there's a user-defined conversion that can create an ItemExtended from an Item. Note, however, that even then, you'll be creating a new instance of ItemExtended.
Inheritance in general doesn't work that way. In managed languages, downcasting only works if the runtime type of your object already is of the derived type. Instances of derived classes inherit all the data and behavior of their ancestor classes, but there's an ancestor doesn't have any knowledge of derived classes. Consider an example, where a derived class introduces a single new field. Firstly, the base class instance is smaller in size, so at the very least, a type cast would require allocating new memory. Second, you would have to decide between changing the runtime type of the original instance (which would be very weird indeed) or making a copy of the old data. The latter way would be very similar to the user-defined conversion scenario, except an user-defined conversion is explicitly invoked, and IMO better that way.
In unmanaged languages, you can of course make any arbitrary conversion you want -- but that just results in catastrophic failures if you do it wrong. In the example above, you would try to access the new field, but since it would not have been allocated for the instance, you would go beyond the boundaries of the object's memory space and access... whatever was in there, be it sensical or not.
If you want to introduce new behavior to existing classes, the C# way is via extension methods. Extension properties aren't there yet, and may never be, so you don't get the property syntax. You may or may not be able to live with that.
You may also find it interesting, that in XAML, the concept of attached properties sort of fits what you are trying to do: you can define arbitrary new properties for whatever -- but if you look at the implementation, what you are really doing is creating a dictionary that maps objects to their associated property values, and the XAML compiler sugarcoats this by making the markup look like you've added the properties to those objects.
You can use OfType instead of Cast:
ItemExtended[] itemsExt = GetItems().OfType<ItemExtended>().ToArray();
You're on the right track with a few adjustments,
use Select() instead of Cast() and
i as ItemExtended rather than (ItemExtended)i
This line should cast it correctly:
ItemExtended[] itemsExt = GetItems().Select(i => i as ItemExtended).ToArray();
I have an arraylist named "ObjectArray" , to do some perfomance improvement and get rid of casting issues , I thought of to use Generic List, how can I convert following arralist to List? I know ToList() will do but how to do in this scenario
public class ObjectArray : ArrayList
{}
ObjectArray col = ObjectArray.Deserialize(xml, Type.type);
Testobject tmo;
tmo= (Testobject)col[i];
You should not be inheritting from List<T>, but Collection<T> instead. Per MSDN docs:
System.Collections.Generic.List is a generic collection designed for
performance not inheritance and, therefore, does not contain any
virtual members.
The Collection class can be used immediately by creating an instance
of one of its constructed types; all you have to do is specify the
type of object to be contained in the collection. In addition, you can
derive your own collection type from any constructed type, or derive a
generic collection type from the Collection class itself.
Inherit from Collection as follows. Inside your class, you can then override (if needed) the basic collection behavior and/or add your own implementation.
public class ObjectArray : Collection<T>
See http://msdn.microsoft.com/en-us/library/ms132397(v=vs.80).aspx
Stop for a second; you are trying to have one class do two things. You are also moving compile-time problems to run-time. I would suggest you deserialize strong types and store them in strongly typed lists rather than everything in one.
i.e.
ViewModel[] viewModels= Serializer.DeserialiseViewModels(fromSomething);
DataModel[] dataModels= Serializer.DeserialiseDataModels(fromSomething);
In anycase, you are concerned with deserializing types and adding them to a list. So don't bother with a new collection class because you don't need to reinvent the wheel here.
SO lets assume you've deserialised an array of objects i.e.
object[] loaded = ObjectArraySerializer.Deserialise(fromSomething);
Now you want to get all the items of type T1 and T2
List<T1> itemsT1 = loaded.OfType<T1>().ToList()
List<T2> itemsT2 = loaded.OfType<T2>().ToList()
Now assuming
where T1: TBase, where T2: TBase
you can do
List<TBase> TBaseItems = itemsT1.Cast<TBase>().Concat(itemsT2.Cast<TBase>()).ToList();
or you could do that straight off the bat;
List<TBase> tbaseItems= loaded.OfType<TBase>().ToList();
I have two classes in different namespaces which I need to type cast.
How to type cast object of one class in another. Both the classes have same method and properties.
May reflection will work?
Any example of typecasting of classes will be helpful.
You cannot cast directly from one type to another, you can do:
a manual mapping
map automatically using reflection (as propery names are the same)
Use AutoMapper
You cannot cast them unless they are related in some way, for example, one is the base of other.
You can map from one to the other in many different ways, one would be by using a mapper, AutoMapper is a well known one
https://github.com/AutoMapper/AutoMapper
This wil map from one to the other based on class member names
Another solution (a part form mapping) in case when the classes are not related in any way, can be use of dynamic.
Event if this is too dangerous, but can be considered like one of possible options:
namepsace A {
public class NotRelatedA() {
public void Run() {}
}
}
namepsace B {
public class NotRelatedB() {
public void Run() {}
}
}
dynamic dyn = new A.NotRelatedA();
dyn.Run(); //Run A
dyn = new B.NotRelatedB();
dyn.Run(); //Run B, without changing and mapping anything
Repeat, this is kind of dangerous, as you leave safe static type world, and jump into the dynamic powerfull mess, so if you use it, use it with causion.
How many properties do those classes have? Are they "hand-written" classes?
Maybe you don't need two classes and can delete one of them and use the other one everywhere?
Maybe one of the classes could derive from the other? Then you will only have to write the common properties and method in the base class.
If you need two distinct classes, and neither derives from the other (this is the situation one msut have for "ordinary" casts (reference conversion casts) to be allowed), you have several options:
Write a constructor overload for one of the classes that takes in an instance of the other class as a parameter, or
Write a static method that "translates" an instance of one class to a new object of the other type, or
You could write a public static explicit operator ClassOne(ClassTwo ct) that did the "translation". With that, it's allowed to use standard cast syntax (i.e. say (ClassOne)variable), or
As others have suggested, you could use a mapping tool, or write your own reflection code that finds the properties that "look alike" a translate between them.