Is it possible to overload constructors in C# so that the program chooses to use one constructor if the argument is of a derived class and a different if it is the base class. For instance
class BaseClass {...}
class DerivedClass : BaseClass {...}
class foo
{
public foo(DerivedClass bar)
{
//do one thing
}
public foo(BaseClass bar)
{
//do another
}
}
That is, I want the program to pick the correct constructor based on the object type.
I agree with everyone else that this feels like a code smell, but if you actually compile your code and run it, you'll find that it already works the way you want it to. For instance, this does exactly what you want it to do, for better or for worse.
class Program
{
static void Main(string[] args)
{
var b = new BaseClass();
var d = new DerivedClass();
var f = new foo(d);
//prints Derived Constructor
var e = new foo(b);
//prints Base Constructor
}
}
public class BaseClass {
public BaseClass()
{
}
}
public class DerivedClass : BaseClass
{
public DerivedClass()
{
}
}
class foo
{
public foo(DerivedClass bar)
{
//do one thing
Console.WriteLine("Derived Constructor");
}
public foo(BaseClass bar)
{
Console.WriteLine("Base Constructor");
}
}
I think the best answer for your question is a bit indirect, but the best proximate answer to your question would be along the lines of this:
Edit: correcting incorrect is syntax usage and making it more specific
public foo(BaseClass foobar) {
if (foobar?.GetType() == typeof(BaseClass)) {
//do something
}
else { // do something different }
}
That being said, I don't think that this is necessarily the optimum way to structure your code; making decisions based on object type can be a signal that it's time to leverage polymorphism via abstract/virtual classes and methods. You're better off IMO doing something like this:
public BaseClass {
public virtual void DoSomething() {...}
}
public DerivedClass : BaseClass {
public override void DoSomething() {...}
}
public foo(BaseClass foobar) {
foobar.DoSomething();
}
If you cast your object in your BaseClass the good constructor will be called.
Like so:
void Main()
{
var object2 = new DerivedClass();
var temp = new Allo((BaseClass)object2);
}
public class Allo
{
public Allo(BaseClass value)
{
Console.WriteLine("baseclass");
}
public Allo(DerivedClass value)
{
Console.WriteLine("derivedclass");
}
}
public class BaseClass
{
}
public class DerivedClass : BaseClass
{
}
Output:
baseclass
When I wrote a simple version of the program shown above, it did correctly choose the derived class-method when the constructor was called with the derived class.
[I was getting strange behavior when I tested as part of my larger project... but I realize now those were due to other errors in my code - a reminder to myself to actually test things - this is the first time in four years I've done any programming so I am forgetting the basics...].
Related
I'm trying to refresh my memory but can't find answers with Google.
public class BaseClass
{
public virtual void DoSomething()
{
Trace.Write("base class");
}
}
public class DerivedClass : BaseClass
{
public override void DoSomething()
{
Trace.Write("derived class");
}
}
If I create an instance of derived class, how do I convert it to it's base class so that when DoSomething() is called, it uses the base class's method only?
A dynamic cast still calls the derived class's overridden method:
DerivedClass dc = new DerivedClass();
dc.DoSomething();
(dc as BaseClass).DoSomething();
Output: "derived class"
Although this sounds irrational but it works
DerivedClass B = new DerivedClass();
BaseClass bc = JsonConvert.DeserializeObject<BaseClass>(JsonConvert.SerializeObject(B));
You can't - that's entirely deliberate, as that's what polymorphism is all about. Suppose you have a derived class which enforces certain preconditions on the arguments you pass to an overridden method, in order to maintain integrity... you don't want to be able to bypass that validation and corrupt its internal integrity.
Within the class itself you can non-virtually call base.AnyMethod() (whether that's the method you're overriding or not) but that's okay because that's the class itself deciding to potentially allow its integrity to be violated - presumably it knows what it's doing.
You absolutely CAN (call the base method), just read up on Polymorphism:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/polymorphism
Example:
public class BaseClass
{
public void DoWork() { }
public int WorkField;
public int WorkProperty
{
get { return 0; }
}
}
public class DerivedClass : BaseClass
{
public new void DoWork() { }
public new int WorkField;
public new int WorkProperty
{
get { return 0; }
}
}
And how to call it:
DerivedClass B = new DerivedClass();
B.DoWork(); // This calls the new method.
BaseClass A = (BaseClass)B;
A.DoWork(); // This calls the old method.
Try using the new keywor instead of override As far as i know this should enable that desired behavior.
I'm not realy sure about that so please don't blame me if i'm wrong!
public class BaseClass
{
public virtual void DoSomething()
{
Trace.Write("base class");
}
}
public class DerivedClass : BaseClass
{
public new void DoSomething()
{
Trace.Write("derived class");
}
}
The solutions with new instead of override break the polymorphism. Recently I came to the same problem and implemented it the following way. My solution has the following advantages:
virtual and override stays in place;
name BaseClass is not used directly in the type cast, so if I introduce an intermediate MiddleClass in the hierarchy between BaseClass and DerivedClass, which also implements DoSomething(); then the MiddleClass's implementation won't be skipped.
This is the implementation:
public class BaseClass
{
public virtual void DoSomething()
{
Trace.Write("base class");
}
}
public class DerivedClass : BaseClass
{
public override void DoSomething()
{
Trace.Write("derived class");
}
public void BaseDoSomething()
{
base.DoSomething();
}
}
The usage is:
DerivedClass dc = new DerivedClass();
dc.DoSomething();
dc.BaseDoSomething();
For VB.net, I've used the following code to do the conversion (shown with Lists of Objects):
Dim tempPartialList As New List(Of clsBaseData)
For Each iterClsDerivedData As clsDerivedData In ListOfDerivedDataObjects
tempPartialList.Add(CType(iterClsDerivedData, clsBaseData))
Next
Where clsBaseData is the Base Class from which clsDerivedData is made by Inheriting clsBaseData.
ListOfDerivedDataObjects is a List(Of clsDerivedData).
I have found this useful where I have Lists of several Derived Classes and I would like to operate on a property of the Base Class for all the objects in the Lists of Derived Classes. The tempPartialList is, for me, a temporary List meant to facilitate changing this property.
With the abstract following class:
public abstract class A
{
public static string MyMethod()
{
return "a";
}
}
Why can't I built this derived abstract class:
public class B<T> where T : A
{
public void AnotherMethod()
{
var S1 = base.MyMethod(); // not allowed
var S2 = T.MyMethod(); // not allowed
}
}
I don't understand why since MyMethod will be available in type T.
There are two misconceptions in your question that collectively prevent both your attempts from working.
First your B class is not in any way derived from the A class, you have only said that it takes a generic parameter that must inherit from A.
Second as the user #recursive pointed out, static methods do not participate in inheritance so MyMethod would only ever be available as A.MyMethod()
You can make at least your first attempt work if you remove the static modifier and make B inherit from A instead of using generics.
// Removed the static modifier
public abstract class A
{
public string MyMethod()
{
return "a";
}
}
// Made B inherit directly from A
public class B : A
{
public void AnotherMethod()
{
var S1 = base.MyMethod(); //base technically isn't required
}
}
Aside from the fact that A.MyMethod is static, which clearly will not work since anything static does not take part in inheritance, even if you made it not static it still will not work. For example, this will not work either:
public abstract class A {
public string MyMethod() {
return "a";
}
}
public class B<T> where T : A {
public void AnotherMethod() {
var S1 = base.MyMethod(); // Line 1
var S2 = T.MyMethod(); // Line 2
}
}
Why?
You are saying where T : A which means that type T has to be a derived type from A. Your class B<T is not a derived type of A so Line 1 will not work.
But why is Line 2 not working?
T is a type and if T is inheriting A, then objects of type T will be able to do that. If you changed it like this, then it will work:
public abstract class A {
public string MyMethod() {
return "a";
}
}
public class B<T> where T : A {
public void AnotherMethod(T t) {
t.MyMethod();
}
}
public class C : A {
}
public class BClosed : B<C> {
public void Foo(C c) {
c.MyMethod();
this.AnotherMethod(c);
}
}
In the above code, C derives A which was your restriction. Then BClosed closes the generic type saying T is C so now you can call MyMethod of A and AnotherMethod of your generic.
Also, when you have a generic class you should use the generic type otherwise I do not see the use. So this is useless since it has no generic code:
public class B<T> where T : A {
public void AnotherMethod() {
}
}
I want to force my child classes to pass themselves as as the generic parameter to the parent class.
For example :
class BaseClass<T> where T: BaseClass
{
//FullClassName : Tuple [Save,Update,Delete]
Dictionary<string,Tuple<delegate,delegate,delegate>> dict = new Dictionary...;
static BaseClass()
{
RegisterType();
}
private static void RegisterType()
{
Type t = typeof(T);
var props = t.GetProperties().Where(/* Read all properties with the SomeCustomAttribute */);
/* Create the delegates using expression trees and add the final tuple to the dictionary */
}
public virtual void Save()
{
delegate d = dict[t.GetType().FullName];
d.Item1(this);
}
}
class ChildClass : BaseClass<ChildClass>
{
[SomeCustomAttribute]
public int SomeID {get;set;}
[SomeCustomAttribute]
public string SomeName {get; set;}
}
public class Program
{
public static void Main(string[] args)
{
ChildClass c = new ChildClass();
c.Save();
}
}
Obviously the above code won't compile. I'll restate : I want the child class to pass itself as the generic parameter and not any other child of BaseClass.
(The above code is kind of a psuedo code and will still not compile).
You can do this:
public class BaseClass<T> where T: BaseClass<T> { }
public class ChildClass : BaseClass<ChildClass> { }
But this doesn't force you to use ChildClass as the generic parameter. You could do this public class OtherChildClass : BaseClass<ChildClass> { } which would break the "coontract" that you want to enforce.
The direct answer is that if your accessing a static method then typeof(T) will give you the type for reflection.
However, there is probably better solutions than using reflection. Options:
1) Static constructor on the child class.
2) Abstract method declared in the base class.
I do not know the application, but I get concerned about my design if I feel like using a static constructor, I also get concerned if a base class needs to initialize the child class.
I suggest looking at injection as a solution rather than inheritance. It offers superior unit testing and often a better architecture.
More info (after initial post), this is my preferred solution:
public interface IRegesterable
{
void Register();
}
public class Widget : IRegesterable
{
public void Register()
{
// do stuff
}
}
public class Class1
{
public Class1(IRegesterable widget)
{
widget.Register();
}
}
Hope this helps
The ConcurrentDictionary is being used as a Set<Type>. We can check in the Set<Type> if the type has been initialized. If not we run RegisterType on the type.
public abstract class BaseClass
{
//Concurrent Set does not exist.
private static ConcurrentDictionary<Type, bool> _registeredTypes
= new ConcurrentDictionary<Type, bool>();
protected BaseClass()
{
_registeredTypes.GetOrAdd(GetType(), RegisterType);
}
private static bool RegisterType(Type type)
{
//some code that will perform one time processing using reflections
//dummy return value
return true;
}
}
public class ChildClass : BaseClass
{
}
There are several inefficiencies with this pattern though.
object.GetType() is pretty darn slow, and inefficient.
Even with the HashSet behavior, we are checking for initialization on each instanciation. Its as fast as I can get it, but its still pretty superfluous.
I have a Function in C# and it have to return the type of the Class. Also in subclasses which extends the class.
Like:
public class A
{
public typeof(this) Method()
{
//Code
}
}
public class B : A {
public override typeof(this) Method() {
//Code
}
}
So the Method in class A should have the return type A. And the Method in class B should have the return tpye B.
Is there a way to do it?
No, this isn't possible. What you're asking for is called a covariant return type, but C# doesn't support this. The closest you can get is either this:
public class A
{
public virtual A Method()
{
//Code returning an A
}
}
public class B : A
{
public override A Method()
{
//Code returning a B
}
}
Which is legal because every B is also an A, or you can use generics instead of inheritance:
public class Foo<T>
{
public virtual T Method()
{
//Code
}
}
And then you can have Foo<A> and Foo<B> -- however, Foo cannot depend on any specifics of T. You can combine this with inheritance, which will sort of achieve what you want:
public class A : Foo<A>
{
// And now A has a Method that returns A
}
public class B : Foo<B>
{
// And now B has a Method that returns B
}
But the problem with this approach is that you will have a hard time actually implementing Method in a meaningful way, because in Foo you cannot use anything specific to the type. To make this explicit, you could make Method abstract:
public abstract class Foo<T>
{
public abstract T Method();
}
public class A : Foo<A>
{
public override A Method()
{
// Code
}
}
public class B : Foo<B>
{
public override B Method()
{
// Code
}
}
I'm having a hard time imagining a scenario where you can actually make use of this, but at least it meets the requirements.
Last but not least, you are not required to use inheritance -- does B really need to derive from A or could you inherit from some common base that does not use Method?
Depending on what your method is trying to do, it might be possible to achieve what you want by using extension methods.
public class A { }
public class B : A { }
public static class AExtension {
public static T Method<T>(this T target) where T: A {
// do your thing here.
return target; // or, return a new instance of type T.
}
}
You can then call Method() and let C# infer the generic argument:
var a = new A();
a = a.Method(); // C# will infer T as A.
var b = new B();
b = b.Method(); // C# will infer T as B.
The downside to this approach is, of course, that you cannot access non-public members of your classes in Method(), unless you use reflection.
There is a way to do this, actually.
class A {
public A Method () { ... return this; }
}
class B : A {
new public B Method () => (B)base.Method();
// or { base.Method(); return this; }
}
Make sure you only use this if you know that the base returns this.
Given
public class A
{
public static void Foo()
{
// get typeof(B)
}
}
public class B : A
{
}
Is it possible for B.Foo() to get typeof(B) in .NET 4? Note that Foo is static.
There is no difference between A.Foo() and B.Foo(). The compiler emits a call to A.Foo() in both cases. So, no, there is no way to detect if Foo was called as A.Foo() or B.Foo().
Unfortunately this isn't possible, as dtb explains.
One alternative is to make A generic like so:
public class A<T>
{
public static void Foo()
{
// use typeof(T)
}
}
public class B : A<B>
{
}
Another possibility is to make the A.Foo method generic and then provide stub methods in the derived types that then call the "base" iplementation.
I'm not keen on this pattern. It's probably only worthwhile if you absolutely need to keep the B.Foo calling convention, you can't make A itself generic, and you have lots of shared logic inside A.Foo that you don't want to repeat in your derived types.
public class A
{
protected static void Foo<T>()
{
// use typeof(T)
}
}
public class B : A
{
public static void Foo()
{
A.Foo<B>();
}
}