How can I call a method for a derived class? - c#

In Short
I want to be able to call a method, the method takes a parameter of type ObservableCollection<Base> but I want to call it with ObservableCollection<Derived>. It says it cannot convert between the two.
Longer
I want to call a WPF Window, in it is a ListBox that will bind to an ObservableCollection. I want the window to display some basic information that are common to two different classes. The classes are Derived1 and Derived2, and are based an BaseClass. I am able to call the method had the type just been BaseClass, but I want to pass a list through.
So I have two collections :
ObservableCollection<Derived1> A;
ObservableCollection<Derived2> B;
And want to be able to call a method like the one below, with the above two collections so I don't need to duplicate code.
public void InitialiseWindow(ref ObservableCollection<BaseClass> List)
{
this.List=List;
}
But it throws an error:
cannot convert from 'ref System.Collections.ObjectModel.ObservableCollection<Derived1>' to 'ref System.Collections.ObjectModel.ObservableCollection<Base>'
Whilst I'm here
Would there be a better way of binding the Collection so changed made in the Window will reflect on the source, instead of using ref?
Solution
I modified the constructor for the Window so that it casts the IEnumerable to a public member of type ObservableCollection. Since the window would only be shown modally, this the member could be accessed after the window closes.
public ObservableCollection<BaseClass> List;
public InitialiseWindow(IEnumerable<BaseClass> List)
{
InitializeComponent();
this.List=new ObservableCollection<BaseClass>(List);
}

If you're exposing it purely for binding purposes, it's sufficient to pass an IEnumerable<BaseClass> reference. The data binding system will automatically inspect the actual instance to see if it implements INotifyCollectionChanged, so it does not need the bound property to be typed explicitly as an ObservableCollection.

Types are different and for ref types must match exactly.
There are cases when you can use derived class in similar way - read on co-variance/contra-variance for C# templates. I.e. you can do
IEnumerable<Object> objects = new List<String>();
because IEnumerable defines it argument as out
public interface IEnumerable<out T> : IEnumerable

Related

Can I create a generic method in c# that accepts a type based on whether it contains a certain method or not?

I want to create a generic method that takes any class that implements a certain method, for example Print(), usually in such a case we need a common interface and then I would say something like : where T : ICustomInterface and the compiler would guarantee that type T contains any methods in that interface. However, in cases where I do not have access to the type, for example I can not modify the List class part of the System.Collections.Generic namespace to implement my interface, can you still achieve this functionality?
However, in cases where I do not have access to the type, for example I can not modify the List class part of the System.Collections.Generic namespace to implement my interface, can you still achieve this functionality?
Try this first:
public class customList<T> : List<T> where T : ICustomInterface{
}
According to SharpLab, it valid code. But you need proper compiler confirmation.
If it does not work, there is the MVVM way: "If you can not modify it, wrap it into something you can modify." Just put a List<T> inside of a custom class as private field and add all the List Functions you want, by simply relaying thhe cals it to the List<T> inside.
Edit:
I wanted to create a generic class that takes anything that implements an indexer, and then have a generic "Peek" method (look forward in a list, array, or anything that contains an indexer) based on the current state of this class etc
Unfortunately, "having a Indexer" is not something Generics can test. In .NET every class can be given a Indexer, as much as it can be given Functions, Fields and Properties.
Reflection can Identify Indexers. I only ever consider Reflection as a fallback, but it is one way.
Despite the checking limits of generics, you can define Indexers in a Interface, as much as you could Functions and Properties. At the end of the day, Indexers are propably mostly Syntax sugar for Function calls like properties are. While doing so would at a first glance exclude the Build-in List types, it is easy enough to sublcass them and have them implement the Interface.
Without being able to add an interface this is going to be pretty hard to accomplish is a type friendly manner. I don't know the usefulness of this, but it could be done:
public void Print(object myObj) {
var method = myObj.GetType().GetMethod("Print");
if (method != null) method.Invoke(this, null);
}
Can’t do what you’re asking exactly. But you could write a wrapper class that allows you to set a delegate for the required method, and use the wrapper in the type constraint.
class Printable
{
protected readonly Action _action;
public Printable(Action printAction)
{
_action = printAction;
}
public void Print()
{
_action();
}
}
void CallPrint<T>(T obj) where T : Printable
{
obj.Print();
}
var wrapper = new Printable( ()=> foo.Print() );
CallPrint(wrapper)(
You could do a similar thing for classes that have indexers, although you would use a Func instead of an Action.

Passing an ObservableCollection<child> to a function that take ObservableCollection<parent>

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 {
...
}

How can I add a property to a class through inheritance and then cast the base class to the new class?

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();

How can I set a Class Public Property as Type List<T>?

I want to define a public property in a User Control with a type of List that I can pass a List to and then have the control bind it to a repeater.
public partial class RepeaterPager : System.Web.UI.UserControl
{
public List<T> DataSource;
}
The from calling code
List<someClass> list = new List<someClass>;
RepeaterPager1.DataSource = list ;
I thought this would be simple, but I am getting Error The type or namespace name 'T' could not be found (are you missing a using directive or an assembly reference?) on the line that declares the public property. What am I doing wrong
Cheers
Stewart
This is only possible if the class containing property is generic. In theory, you could use generic method:
void SetDataSource<T>(List<T> dataSource)
but you'll lose type information elsewhere.
Maybe,
IEnumerable DataSource
will be a better option?
You can't have generic parameters in fields of a class with out the class being generic.
See this answer for info on making a usercontrol generic: C# generics usercontrol
Or you could just use a non-generic version, such as IEnumerable or IList.
You either need to define generic Type, or make RepeaterPager generic
public partial class RepeaterPager<T> : System.Web.UI.UserControl
{
public List<T> DataSource;
}
The general pattern for this type of data binding is to define DataSource as type object. Then, in the set method you can do a runtime check to verify the object is of a type you expect -- throw an exception or debug assert otherwise.
Besides, Repeater.DataSource is type object anyways ...
Many times I can get away without holding a reference to the datasource, so I pass it directly to the control:
public object DataSource
{
get { return myRepeater.DataSource; }
set {
if (value is IEnumerable) // or whatever your requirement is, if needed
myRepeater.DataSource = value;
else
throw new NotSupportedException("DataSource must be an IEnumerable type");
}
}
However, if you really do need to know about the type T, I would consider the following:
If possible, use the generic class idea others have suggested.
If you need to repeat this pattern for different classes, build a base class or Interface for all your data sources to derive from
Use DataSource as type object, but just grab the type at run time using obj.GetType(). (Depending on your needs this may or may not work)

Converting from an interface to an object that implements the interface?

I have an interface which is implemented by several different objects. What I am trying to do is write a method in c# that will accept the interface object as a parameter and convert this parameter to an object that it implements so i don't have to write the same function for several different types. Such as:
Class UnappliedCashDetails implements interface ITransactionDetail.
Constructor for ISSBatch:
public ISSBatch(List<ITransactionDetail> details)
public static ISSBatch GetNextReceiptBatch()
{
List<UnappliedCashDetail> details = new List<UnappliedCashDetail>();
/`*`some code here to populate my list`*`/
return = new ISSBatch(details);
}
C# does not like this. Am i trying to use the interface wrong or just not casting correctly?
Thanks!
You're passing a List<UnappliedCashDetail> to a constructor that accepts List<ITransactionDetail>. UnappliedCashDetail may very well implement ITransactionDetail, but this type of variance is not supported by C#. Consider that inside the constructor (or any other method) you could attempt to add an instance of SomeOtherTransactionDetail to your details list, except that the details list should really only accept UnappliedCashDetail, as per its declaration.
To make your code work, you need to change your declaration
List<ITransactionDetail> details = new List<ITransactionDetail>();
/* some code here to populate my list */
return new ISSBatch(details);
Or you could simply change your constructor to accept IEnumerable<ITransactionDetail>, in which case your original List<UnappliedCashDetail> declaration would work. Variance is supported for IEnumerable<T> (note: C# 4), since it is just a sequence and cannot be added to, deleted from, etc., so there's no possibility of trying to add an AppliedCashDetail instance to a sequence of UnappliedCashDetail objects.

Categories