C# - Call subclass with a subobject - c#

See the code below.
In the base handler (MyBaseHandler) I have a handler of all objects of MyBaseClass.
Then I have a subclass handler (HandlerA) where I want to handle the objects of class ClassA.
So I want to override the base handler for class ClassA; all other classes should have the base handling.
But this does not work as expected. The base Handle(MyBaseClass) is called for all the objects, including objA where I want to use Handle(ClassA).
I would like this generic handing so I can easily extend with other handling for other classes as needed. This code compiles. If I add the "override" keyword to the Handle in HandlerA it will not compile.
How can achieve what I want with the simplest code? Is it possible to achieve this without a lot of code to check the type of the class? Is it possible to use generics to achieve this?
abstract class MyBaseClass {}
class ClassA : MyBaseClass {}
class ClassB : MyBaseClass {}
class ClassC : MyBaseClass {}
class ClassD : MyBaseClass {}
abstract class MyBaseHandler
{
public void Go()
{
ClassA objA = new ClassA();
Handle(objA);
ClassB objB = new ClassB();
Handle(objB);
ClassC objC = new ClassC();
Handle(objC);
ClassD objD = new ClassD();
Handle(objD);
}
public virtual void Handle(MyBaseClass obj)
{
...
}
}
public class HandlerA : MyBaseHandler
{
public void Handle(ClassA obj)
{
// This code does not get called.
...
}
public void Run()
{
Go();
}
}

MyBaseHandler only knows about Handle(MyBaseClass obj). It doesn't matter that Handle has the same name as a method in MyBaseHandler, or even that the signatures are compatible. If you were to override Go in HandlerA, your code would work as expected, but as it is, MyBaseHandler can never resolve to a method defined in a sub-class.
You are on the right track making the method virtual in MyBaseHandler, but you need to follow through and create an override in HandlerA:
class HandlerA : MyBaseHandler
{
public override void Handle(MyBaseClass obj)
{
if (obj is ClassA)
{
Handle(obj);
return;
}
base.Handle(obj);
}
public void Handle(ClassA obj)
{
// This code gets called by override void Handle(MyBaseClass obj)
}
// ...
}
Since Handle(MyBaseClass obj) matches the signature of the base class, you are able to override and MyBaseHandler can "see" the method. You can then check if obj is an instance of ClassA and go from there.

This is not going to work, because compiler expects method with signature indicating MyBaseClass as argument. If you want to override it, the signature should be the same, so in HandlerA it should be override void Handle(MyBaseClass obj). ClassA inherits from MyBaseClass, so it will still take it as argument. You can then cast it inside function if you need it to be ClassA.
public override void Handle(MyBaseClass obj)
{
ClassA objA = obj as ClassA;
if(objA == null)
{
throw new ArgumentNullException("Argument to this handler should be ClassA") ;
}
// your code
}

Related

Override method from instance of the class

I have a merly simple question, but seems cant find an answer for it, I want to know if its possible to override a method from a instance class structore would look like this:
public class A : baseA
{
public virtual void methodA()
{
}
}
public class B : baseB
{
public void method B()
{
var ClassA = new A();
}
/* Now Is there some sort of overide like */
public override methodA()
{
//Do stuff
}
}
And those classes do not inherit from each other, to make it more difficult.
Now if this sort of construction is possible in c#?
No. You cannot override a class's behavior if you don't inherit from it.
The override modifier is required to extend or modify the abstract or virtual implementation of an inherited method, property, indexer, or event.
Class B must inherit from class A in order to do so.
public class A
{
public virtual void methodA()
{
}
}
public class B : A
{
public void methodB()
{
var ClassA = new A();
}
public override void methodA()
{
//Do stuff
}
}
Check MSDN for more details:
An override method provides a new implementation of a member that is inherited from a base class. The method that is overridden by an override declaration is known as the overridden base method. The overridden base method must have the same signature as the override method

Set generic type property in derived classes

I have a generic type G<T> where T : A, where A is an abstract class. In each class B derived from A I want to have a field of type G<B>, without writing repetetive code, however I'm not sure if it's even possible. One way to do this would be
abstract class A
{
protected object g;
protected abstract void SetG();
public A()
{
SetG();
}
}
class B : A
{
protected override void SetG()
{
this.g = new G<B>();
}
public B() : base() {}
}
But this would mean a lot of repetetive code in every derived class. Is there a better way to do this?
You could add an extra abstract class in between:
public abstract class A<T> : A where T : A
{
protected override void SetG()
{
this.g = new G<T>();
}
}
...then, update your B declaration to:
public class B : A<B>
{
public B() : base() { }
}
I believe that what you are trying to do is a Covariant Conversion. See this MSDN article on using delegates and see if that works for you. Look in the section "Using Delegates with Covariant Type Parameters".
In your A:, create a delegate:
Func<G<A>> GetG;
Then, in your derived classes, set this func pointer to a function of type
Func<G<B>>
Bingo!

C# inherited class from generic as a type

I've got an issue with generics. I've those classes :
abstract class BaseTestClass<T> : where T : class, new()
{
//base test class implementation
public abstract void Run(BaseDataClass<T> data);
}
class BaseDataClass<T> : where T : class, new()
{
//base data class implementation
}
class DataA : BaseDataClass<SettingsA>
{
//some stuff
}
class TestA : BaseTestClass<SettingsA>
{
//Works!
public override void Run(BaseDataClass<SettingsA> data)
{
}
//Doesn't Work!
public override void Run(DataA data)
{
}
}
My question if why can't I use the inherited class in the abstract method ?
[EDIT]
The error at compilation is:
TestA does not implement inherited abstract member Run(BaseDataClass)
You can, but the BaseTestClass<SettingsA> base class simply does NOT have a method to override of the signature Run(DataA), but only one of the signature Run(BaseDataClass<DataA>).
The generic inheritance also means that the generic T type is the same.
You can implement this with an additional generic argument, Type-Safe and without cast:
internal abstract class BaseTestClass<T, Y>
where T : class, new()
where Y : BaseDataClass<T>
{
private T m_data;
//base test class implementation
public abstract void Run(Y data);
}
public class BaseDataClass<T> where T : class, new()
{
}
internal class TestA : BaseTestClass<SettingsA, DataA>
{
public override void Run(DataA data)
{
throw new NotImplementedException();
}
}
class DataA : BaseDataClass<SettingsA>
{
}
class SettingsA
{
}
This is type-safe because the constraint is
where Y : BaseDataClass<T>
If you don't need T directly in you base class, you can only use one generic parameter and remove T
Your second method does not compile because there is no method to be overriden by it, removing the override modificator will make your code compile.
If you want to have a method which will run only when the parameter is of type DataA, but still execute the interface method implementation, you can do this way:
class TestA : BaseTestClass<SettingsA>
{
//Works!
public override void Run(BaseDataClass<SettingsA> data)
{
}
public void Run(DataA data)
{
//dp some stuff
Run((BaseDataClass<SettingsA>)data);
}
}
But note that this is not bullet proof, you could miss boxed calls, the better way is do this way:
class TestA : BaseTestClass<SettingsA>
{
//Works!
public override void Run(BaseDataClass<SettingsA> data)
{
var myDataA = data as DataA;
if (myDataA != null)
{
//your parameter is a DataA;
}
}
}
It does not work because you cannot override one method with two methods. Take the override off of one of the methods in TestA, and it will all work. There's no point in overriding a single method twice, anyhow, within a single class.

Cannot change return type when overriding method, error when using generics

I am having trouble overriding a method that returns a generic class that is strongly typed.
This is just setting up for the example below
public class Something : ISomething {}
public interface ISomething {}
My issue is with the Clone method below, only the second one works.
public class ClassA : AbstractClass<Something>
{
public override ClassA Clone() // <--- this doesn't work
{
return this; // this is just dummy code
}
public override AbstractClass<Something> Clone() // <-- this works
{
return this; // this is just dummy code
}
}
public abstract class AbstractClass<T> where T : ISomething
{
public abstract AbstractClass<T> Clone();
}
I would prefer to have the first Clone method, as the name of the class doesn't change. But only the second method compiles. Is there any way to avoid this?
The first override changes the actual signature:
Your method on the base class establishes that it will return an AbstractClass<T>.
Since your subclass says that T is going to be something, this now implies that the method returns an AbstractClass<Something>. While ClassA is an AbstractClass<Something> that doesn't mean that all AbstractClass<Something> are a ClassA.
Consider the following example:
AbstractClass<Something> myVar = new ClassA(); // works, because ClassA is an AbstractClass<Something>
// Now we hold a reference to an AbstractClass<Something>
myVar.Clone(); // => This should return an AbstractClass<Something> not ClassA
Extending the example: consider a ClassB:
public class ClassB : AbstractClass<Something> {}
Both ClassA and ClassB are AbstractClass<Something>. If we retake the first example:
AbstractClass<Something> myVar;
myVar = new ClassA();
myVar = new ClassB();
// Here you don't know whether it's a ClassA or ClassB, you only know it's an `AbstractClass<Something>`
myVar.Clone();
You could add another generic parameter for the return type:
public abstract class AbstractClass<TC, T> where TC: AbstractClass<TC, T> where T : ISomething
{
public abstract TC Clone();
}
then change ClassA to:
public class ClassA : AbstractClass<ClassA, Something>
{
public override ClassA Clone()
{
return this;
}
}
It is impossible to change the return type while overriding a method.
You could remove the override from the first implementation, and this will define a new method. But, because you have that abstract Clone method in the base class, you are forced to implement it as well, and you'll end up with 2 methods with the same name, and the same parameters, so the code will not compile.
Do you really need that Clone method in the abstract class ?
I think you should remove the Clone method from the abstract class, and add the Clone method in the derived class (perhaps also implementing ICloneable interface).

Override abstract method with another one, having different parameters

I have an abstract class ClassA, with an abstract method that takes a paramter of type ClassB. Several classes derive from it. Now I add another project, which has similar functionality, but needs a slightly different base ClassA, to derive its several classes from. The main difference: The new base class, ClassC, shouldn't ClassB as argument, but another one, that's derived from B, ClassD. ClassC should then be used as base by several classes again.
Is this possible? This is more of a question out of curiousity. I know it is possible with generics, by doing this:
public abstract void Method1<T>(T parameter) where T : ClassB;
...
public override void Method1<ClassB>(ClassB parameter) {
Is it possible without generics? And is there any dowside to them, aside from having to type the type twice?
abstract class ClassA
{
public abstract void Method1(ClassB parameter);
}
class DerivingClasses1 : ClassA
{
public override void Method1(ClassB parameter)
{
// do something
}
}
// -------
abstract class ClassC : ClassA
{
// This would have to override Method1 of ClassA somehow,
// instead of overloading it.
public abstract void Method1(ClassD parameter);
}
class DerivingClasses2 : ClassA
{
public override void Method1(ClassD parameter)
{
// do something
}
}
// -------
class ClassB
{
}
class ClassD : ClassB
{
}
In my opinion, the best approach would be to override the base class method with a sealed implementation that invokes the overload with the new parameter type, thereby insulating the user from the type conversion.
abstract class ClassC : ClassA
{
public override sealed void Method1(ClassB parameter)
{
this.Method1(parameter as ClassD);
}
public abstract void Method1(ClassD parameter);
}
Edit: If used in production, you should perform proper type checking in order to avoid getting unexpected nulls:
abstract class ClassC : ClassA
{
public override sealed void Method1(ClassB parameter)
{
if (!(parameter is ClassD))
throw new ArgumentException(
"Parameter must be of type ClassD.", "parameter");
this.Method1((ClassD)parameter);
}
public abstract void Method1(ClassD parameter);
}
Just implement both methords in ClassC.
Override abstract method with another one, having different parameters
This is not really possible, however you could use a common interface:
interface IMyType {}
class MyTypeBase
{
public abstract void Method1(IMyType parameter);
}

Categories

Resources