I have few classes which inherits from a generic class like FooBasePolicy<TFooTarget>. And I want to cast my derived classes by their base class (not sure if its right way to say it). My classes are:
public class FooTarget{}
public class GTeamTarget : FooTarget{}
public class MTeamTarget : FooTarget{}
public class FooBasePolicy{}
public class FooBasePolicy<TFooTarget> : FooBasePolicy where TFooTarget : FooTarget
{
public virtual TFooTarget SomeFooTarget { get;set; }
}
public class GTeamPolicy : FooBasePolicy<GTeamTarget>
{
public GTeamPolicy()
{
SomeFooTarget = new GTeamTarget();
}
}
public class MTeamPolicy : FooBasePolicy<MTeamTarget>
{
public GTeamPolicy()
{
SomeFooTarget = new MTeamTarget();
}
}
And then I tried to use these this way,
problem is I don't know upfront which TeamTarget it is. It can be G or M.
FooBasePolicy<FooTarget> policy = null;
if (something.Equals("GTEAM"))
{
//This gives me an implicit conversion error. It can't cast.
policy = FromBinary(type, funnelData.Data) as FooBasePolicy<FooTarget>;
}
else if (something.Equals("MTEAM"))
{
policy = FromBinary(type, funnelData.Data) as FooBasePolicy<FooTarget>;
}
FromBinary actually returns a deserialized object.
But it perfectly can cast into FooBasePolicy. But then I miss SomeFooTarget property.
Any idea? Please help.
As the others said, just define an interface:
public interface IFooBasePolicy<out TFooTarget> {
TFooTarget SomeFooTarget { get; }
}
The base class FooBasePolicy now looks like:
public class FooBasePolicy<TFooTarget> : IFooBasePolicy<TFooTarget>
where TFooTarget : FooTarget {
public virtual TFooTarget SomeFooTarget { get; set; }
}
Later you can use the following cast:
policy = ((IFooBasePolicy<FooTarget>)FromBinary(something));
Short explanation:
FooBasePolicy<FooTarget> is not a base class of FooBasePolicy<GTeamTarget>
this can be resolved with covariance: GTeamTarget is a subtype of FooTarget, therefore FooBasePolicy<GTeamTarget> is a subtype of FooBasePolicy<FooTarget>
but covariance is only allowed on interfaces in C#
so you need an interface with a coveriant type declaration
Related
I have Bills and Receipts. Both types have a property called Lines, but Receipt.Lines is full of ReceiptLines and Bill.Lines is full of BillLines. I'd like them to both inherit from a class called Document with a property Lines that's full of DocumentLines so that I can occasionally pass them to functions that operate on Documents, but I don't want to have to myReceipt.Lines.Select(line => (ReceiptLine)line) each time I am specifically using a Bill or Receipt. Is there an elegant way to do this?
Note that the following attempt results in CS1503 Argument 1: cannot convert from 'Receipt' to 'Document<DocumentLine>'
void Main()
{
var something = new Receipt();
DoStuff(something);
}
public void DoStuff(Document<DocumentLine> document) { }
public abstract class DocumentLine { }
public class BillLine : DocumentLine { }
public class ReceiptLine : DocumentLine { }
public abstract class Document<TDocLine> where TDocLine : DocumentLine
{
public List<TDocLine> Lines { get; set; }
}
public class Bill : Document<BillLine> { }
public class Receipt : Document<ReceiptLine> { }
Note that you cannot change a type when overriding, but you can make the line type a generic parameter.
public abstract class DocumentLine { ... }
public class BillLine : DocumentLine { ... }
public class ReceiptLine : DocumentLine { ... }
public abstract class Document<TDocLine> where TDocLine : DocumentLine
{
public List<TDocLine> Lines { get; set; }
}
public class Bill : Document<BillLine> { ... }
public class Receipt : Document<ReceiptLine> { ... }
Deriving the line types from a common base has advantages. 1) you can reuse stuff common to both line types. 2) You can limit the actual types of TDocLine. This safer as it disallows you to specify an inappropriate type and it allows you to access the common members declared in DocumentLine from other methods in the Document<TDocLine> class.
You could use a generic type to define the List item type, like so:
interface DocumentLine { }
class BillLine : DocumentLine { }
class ReceiptLine : DocumentLine { }
class Document<T> where T : DocumentLine
{
public List<T> Lines { get; set; }
}
class Bill : Document<BillLine> { }
class Receipt : Document<ReceiptLine> { }
Edit: What the new implied question is referring to is called 'Generic Covariance'. In C# generic covariance is limited to interface and delegate types [see out keyword (generic modifier)].
Instead, to get the behavior you want, you'll have to carry the generic variable as generic with conditions, rather than a fixed covariant type.
public void DoStuff<T>(Document<T> document) where T : DocumentLine { }
Let's say I have a class A with the property "Details" that return an instance of class B.
public class A
{
public virtual B Details {get; set;}
}
Lets say also, I have a class Aext (A extended) that inherits from A.
But I want that Aext.Details return an instance of class Bext (B extended) :
public class Aext : A
{
public override Bext Details {get; set;}
}
This will not compile because the type Bext must match the type inherited from A.
Of course, I can easily solve that by just put B as return of Details for Aext.
public class Aext
{
B Details {get; set;}
}
Assignment will work, but I'll have to check everytime I use an instance of Aext if Details is Bext or B.
Do you see a way of doing something cleaner that this solution ?
Thank you.
Maybe you can try generics, something like this:
public class A<T> where T : B
{
public T Details { get; set; }
}
public class Aext : A<Bext>
{
}
public class B
{
}
public class Bext : B
{
}
If you need you can override T Details with Bext Details, it will work fine.
No - but I think therefore it indicates the base class is flawed in its design. You are trying to force Interface behaviours onto an Abstract class/method. The base method does nothing, do what exactly is being inherited ? The base class could have a protected member of type B accessed by each inheritor and exposed via their own strongly typed accessor method. The value would be available to all inheritors, but consumers would need to get/set a strongly typed version of the data.
If you do not want to introduce interfaces, you can do something like this:
public class B
{ }
public class Bext : B
{ }
public class A
{
public virtual B Details { get; set; }
public A()
{
Details = new B();
}
}
public class Aext : A
{
public override B Details => new Bext();
}
However, I would suggest you go with composition and use dependency injection, like this:
public interface IB
{ }
public class B : IB
{ }
public class Bext : IB
{ }
public class A
{
public virtual IB Details { get; set; }
public A(IB details)
{
Details = details;
}
}
public class TestClass
{
public void TestMethod()
{
IB details = new B();
IB extDetails = new Bext();
A instance1 = new A(details);
A instance2 = new A(extDetails);
}
}
This way, you do not need to extend the inheritance hierarchy by creating Aext class. You can contain that strictly to the properties in question.
I'm with problems to convert from the type derived to base type using Generics.
Class to manage the dictionary:
public class ManagerDictionary<TContext>
{
public ManagerDictionary()
{
this.Dictionary = new Dictionary<int, TContext>();
}
public IDictionary<int, TContext> Dictionary { get; private set; }
public void Register<TSubContext>(int context, TSubContext subContext) where TSubContext : TContext
{
this.Dictionary[context] = subContext;
}
}
Interface of the Process context:
public interface IProcessContext : IContext<ProcessViewModel>
{
}
My test class:
public class Foo<TViewModelContext> where TViewModelContext : ViewModeBase
{
public Foo(IProcessContext processContext)
{
// Create de Dictionary Manager.
this.ManagerDictionary = new ManagerDictionary<IContext<TViewModelContext>>();
// Register the process context on dictionary.
// The error is occurring here: The is no implicit reference conversion from 'IProcessContext' to 'IContext<TViewModelContext>'
this.ManagerDictionary.Register((int)ContextType.Process, processContext);
}
protected ManagerDictionary<IContext<TViewModelContext>> ManagerDictionary { get; set; }
}
When I try register the processContext, the problem occurs:
The is no implicit reference conversion from 'IProcessContext' to
IContext<TViewModelContext>
How can I resolve this problem?
Edit:
When I Create a inherited class of the Foo, I can register, but I need register on Foo class too.
public interface IAnotherProcessContext : IContext<ProcessTwoViewModel>
{
}
public class InheritedFoo : Foo<ProcessTwoViewModel>
{
public InheritedFoo(IAnotherProcessContext anotherProcessContext)
{
base.ManagerDictionary.Register((int)ContextType.InheritedProcess, anotherProcessContext);
}
}
You're trying to treat IContext<T> as if it's covariant with respect to T, but that interface isn't defined as being covariant.
Either make the interface be covariant, or alter your program such that you never expect an IContext<Child> to be implicitly convertible to an IContext<Parent>.
I am currently in the middle of self-teaching some basic concepts of C# and I am experimenting with abstract classes and polymorphism. I thought I got the basic concept but it turned out that the concept doesn't work like I understood it :). However - I hope I get some answers which clear the dust a little bit :).
The whole task I am trying to achieve is to extend an abstract base class and use the extension with an object of the base class. Like here:
I have an abstract class which implements an abstract property like:
public abstract class BaseClass
{
public abstract MyProperty mP{get;}
}
where the property is
public abstract class MyProperty
{
public abstract string PropertyName{get;}
}
Now I am deriving the MyProperty class for an actual implementation like
public class DerivedProperty : MyProperty
{
public override string PropertyName
{
get
{
return this._name;
}
}
private _name = "Property1";
/* some other implementation follows here...... */
}
As I've understood polymorphism and inheritance it should now be possible to instantiate a derived class from BaseClass and override the property MyProperty with an object of DerivedProperty like this:
public class DerivedClass : BaseClass
{
public override DerivedProperty mP
{
get
{
return dP;
}
}
private DerivedProperty dP = new DerivedProperty();
/* more implementation follows here...... */
}
Because DerivedProperty is an object of MyProperty and DerivedProperty at the same time it is possible to use it where either MyProperty or DerivedProperty is referenced. At least that's what I thought but it seems that this is wrong.
Now I am wondering - why is polymorphism so useful when something like above is not possible? Because even when I try something like this:
public class DerivedClass : BaseClass
{
public override MyProperty mP
{
get
{
return dP as DerivedProperty;
}
}
private DerivedProperty dP = new DerivedProperty();
/* more implementation follows here...... */
}
I still get only my base object MyProperty and not my extended object DerivedProperty which I want to get.
I know why I get those results - I just don't seem logical to me :). Is it really like polymorphism is supposed to work or is my implementation just crap and I have to do it in a different way to get my extended property?
Appreciate your help here!
You have to provide the same type for overrided property. You can use it later in your abstract BaseClass. Parameters as well as return value of member have to be the same when overriding. It is usually not a problem.
I've prepared following examples that my code look similar to yours.
In some scenarios I've seen that there is added second property with more specific type and different (more specific) name:
public abstract class BaseCar
{
public abstract BaseDriver Driver { get; }
}
public abstract class BaseDriver
{
public abstract string Name { get; set; }
}
public class AgressiveDriver : BaseDriver
{
public override string Name { get; set; }
}
public class FastCar : BaseCar
{
private AgressiveDriver _agressiveDriver = new AgressiveDriver();
public override BaseDriver Driver { get { return _agressiveDriver; } }
public AgressiveDriver AgressiveDriver { get { return _agressiveDriver; } }
}
Second approach is to use generics:
public abstract class BaseCar<TDriver>
where TDriver : BaseDriver
{
public abstract TDriver Driver { get; }
}
public abstract class BaseDriver
{
public abstract string Name { get; set; }
}
public class AgressiveDriver : BaseDriver
{
public override string Name { get; set; }
}
public class FastCar : BaseCar<AgressiveDriver>
{
private AgressiveDriver _agressiveDriver = new AgressiveDriver();
public override AgressiveDriver Driver { get { return _agressiveDriver; } }
}
but I think first approach is better because there is no problem with creating/using BaseCar objects (for example to create BaseCar<> variable you have to specify type parameter). Also it makes sense to create more specific name for more specific property.
I think you have an extra bit of complexity you don't need. You have an abstract class inside an abstract class. If you are just learning/relearning this you have skipped a couple easy steps for understanding. Here's a simpler example to start with.
public abstract class Shape
{
public abstract double GetArea();
public abstract double Circumference();
}
public class Square: Shape
{
public double width {get; set;}
public override double GetArea()
{
return width * width;
}
public override Circumference()
{
return width * 4;
}
}
You can now instantiate a Square or create a Circle Class and be able to use either where you use Shape.
I have seen this kind of definition in a library I'm using. I got crazy about the where TObjectType: CSObject. It is obvious that It seems I can use the same time in the constraint because it works and compiles but what does this really mean?
public class CSList<TObjectType>: CSList, IList<TObjectType>, IList
where TObjectType: CSObject<TObjectType>
It means that the TObjectType here must inherit from CSList<TObjectType>.
Usually you use this construct to get typed methods and properties on the base class that adjust to the actual derived classes you intend to use.
To declare such a derived class:
public class SomeDerivedClass : CSList<SomeDerivedClass>
Example:
public class Base<T>
{
public T[] Values { get; set; }
}
public TestCollection : Base<TestCollection>
{
// here, Values inherited from Base will be:
// public TestCollection[] Values { get; set; }
}
public OtherCollection : Base<OtherCollection>
{
// here, Values inherited from Base will be:
// public OtherCollection[] Values { get; set; }
}