I have a class library which contain some base classes and others that are derived from them. In this class library, I'm taking advantage of polymorphism to do what I want it to do. Now in a consuming application, I want to change the behavior of some code based on the runtime type of the child classes. So assume the following:
public class Base { }
public class Child1 : Base { }
public class Child2 : Base { }
Now in the consuming application I want do something as follows (note that all of the following classes are in the consuming application and cannot be referenced in the class library):
public interface IMyInterface1 { }
public interface IMyInterface2 { }
public static class Extensions
{
public static void DoSomething(this Base myObj, Object dependency)
{
}
public static void DoSomething(this Child1 myObj, Object dependency)
{
IMyInterface1 myInterface = dependency as IMyInterface1;
if (myInterface != null)
{
//Do some Child1 specific logic here
}
}
public static void DoSomething(this Child2 myObj, Object dependency)
{
IMyInterface2 myInterface = dependency as IMyInterface2;
if (myInterface != null)
{
//Do some Child2 specific logic here
}
}
}
UPDATE:
This does not work. It always calls the extension method of the base class. Is there some other way that will allow me to do this and avoid having to explicitly check for the runtime type? The reasons is because more classes that are derived from the Base could be added and corresponding extension methods could come from some other external assembly.
Thanks in advance.
As #SLaks has already stated you cannot call the method as an extension method (even with a dynamic type) ... you can however call the static method with a dynamic type
So, although this will fail
Base base1 = new Child1();
(base1 as dynamic).DoSomething();
This will work
Base base1 = new Child1();
Extensions.DoSomething(base1 as dynamic);
No, that won't work.
Extension methods are statically dispatched, using the same mechanism as overload resolution.
If you have a variable of compile-time type Base, the compiler will always call the base extension method, regardless of the runtime type.
Instead, you can make the base extension method check the runtime type and call the appropriate other extension method.
I was looking for the same thing just now.
You could add one more method to your extension class like this:
public static void DoSomething(this Base myObj, Object dependency)
{
if(myObj.IsSubclassOf(Base))
{
// A derived class, call appropriate extension method.
DoSomething(myObj as dynamic, dependency);
}
else
{
// The object is Base class so handle it.
}
}
You don't need the if/else check if the base class is abstract (or never used in the wild):
public static void DoSomething(this Base myObj, Object dependency)
{
DoSomething(myObj as dynamic, dependency);
}
[Edit] Actually this won't work in your case as you don't implement support for all derived objects (so could still get infinite recursion). I guess you could pass something to check for recursion but the given answer is the simplest. I'll leave this here as it might spark more ideas.
Below is the minimal example showing how to mimic polymorphism with extension methods.
void Main()
{
var elements = new Base[]{
new Base(){ Name = "Base instance"},
new D1(){ Name = "D1 instance"},
new D2(){ Name = "D2 instance"},
new D3(){ Name = "D3 instance"}
};
foreach(Base x in elements){
x.Process();
}
}
public class Base{
public string Name;
}
public class D1 : Base {}
public class D2 : Base {}
public class D3 : Base {}
public static class Exts{
public static void Process(this Base obj){
if(obj.GetType() == typeof(Base)) Process<Base>(obj); //prevent infinite recursion for Base instances
else Process((dynamic) obj);
}
private static void Process<T>(this T obj) where T: Base
{
Console.WriteLine("Base/Default: {0}", obj.Name);
}
public static void Process(this D1 obj){
Console.WriteLine("D1: {0}", obj.Name);
}
public static void Process(this D2 obj){
Console.WriteLine("D2: {0}", obj.Name);
}
}
Outputs:
Base/Default: Base instance
D1: D1 instance
D2: D2 instance
Base/Default: D3 instance
If you can not use the keyword "dynamic" (older version of .NET), you can use reflection to achieve the same thing.
In place of :
Base base1 = new Child1();
Extensions.DoSomething(base1 as dynamic);
you can write :
Base base1 = new Child1();
MethodInfo method = typeof(Extensions).GetMethod("DoSomething", new System.Type[] { base1.GetType() });
if (method) {
method.Invoke(new object[] { base1 });
}
Related
public abstract class Base
{
public Base ClassReturn()
{
return this;
}
}
Is there possibility to return child type that invoked ClassReturn method?
I've done that in extension method:
public static T ClassReturn<T>(this T obj) where T : Base
{
return (T) obj.ClassReturn();
}
But I want to embeed it in Base class instead of extension method. Is there possibility to do that with generics?
I will copy my comment which describes what I want to achieve:
I need something similiar to builder pattern and I have different
classes that depending on previous operations do something else, now I
want to have a similiar functionality in every of them and when I use
it I lose object type. So my solution is either implement that
functionality multiple times in every class or create extension
method. But I always thought when it is possible to make extension
method for class then I can embeed that in class, but as I see it is
not possible.
Full example:
public class Child1 : Base
{
public Child1 Operation1()
{
Console.WriteLine("operation1");
return this;
}
}
public class Child2 : Base
{
public Child2 Operation2()
{
Console.WriteLine("operation2");
return this;
}
}
static void Main(string[] args)
{
Child1 ch = new Child1();
ch.Operation1().Operation1().ClassReturn().Operation1()
}
I can't use Operation1 after ClassReturn if I don't use extension method.
Try this one:
public abstract class Base<T> where T: Base<T>
{
public T ClassReturn
{
get { return (T)this; }
}
}
public class Child1 : Base<Child1>
{
}
public class Child2 : Base<Child2>
{
}
From your question and your comments, what you are trying to achieve is not possible directly from the type system. By returning an instance of Base you are specifically saying that all you are interested is that you have something that derives from Base, but that the specific class doesn't matter. Statically, the compiler no longer has the information it needs to perform a cast.
If you are trying to get the original type back statically, then you have to supply the information to the compiler, and in this case you can't guarantee that you have the correct information. In the example below, the instance is created from derived type A but attempted to be cast to derived type B through the extension, the compiler will allow the code to compile, but you'll get an exception at runtime.
public class A : Base { }
public class B : Base { }
public static class BaseExtensions
{
public static T GetAsT<T>(this Base base) where T: Base
{
return (T)base;
}
}
public static void Main()
{
Base obj = new A();
B b = obj.BaseAsT<B>(); // This compiles but causes an exception
}
You should look up the Liscov Substitution Principle to get information on how to properly work with base and derived classes in the system as a whole, and then write up a question dealing specifically with the result you are trying to achieve.
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.
public abstract class A
{
// constructors omitted
public abstract A Create(SomeData data);
}
public class B : A
{
// constructors omitted
public override A Create(SomeData data)
{
return new B(data);
}
}
What I want is to be able to make the Create method static, so that I can get an instance of B without having to create a useless instance with an empty constructor. (If you're wondering why, A is actually a generic type of the form A<TFoo, TBar>, where TBar corresponds to the derived types. As we all know, you can't instantiate a generic type using a constructor that takes any arguments.)
I am already aware that static methods are decoupled from the object hierarchy, only relying on the name of the type. That means I can't have Create as an abstract method that I force all descendants to implement. Is there another way I can implement this pattern?
Something like this might work, depends on your requirements
public abstract class A
{
public string Data { get; set; }
public static T Create<T>(string data) where T : A, new()
{
return new T() { Data = data };
}
}
public class B : A { }
then can do
A foo = A.Create<B>("foo");
There is simply no way to do this. Inheritance is based off of instance methods in C# and has no equivalent feature for static methods. Another way to implement this pattern though is to require a lambda in lieu of a static method.
For example (you mentioned the actual type was A<TFoo, TBar>)
void UseIt<TFoo, TBar>(A<TFoo, TBar> p, Func<SomeData, TBar> func) {
TBar b = func();
...
}
The consumer doesn't care if Create is static, instance or even called create. Generally all they care about is having a function which takes a SomeData and returns a TBar. Delegates fit this pattern exactly.
Why is this not possible?
abstract class A
{
public abstract T f<T>();
}
class B<T> : A
{
public override T f()
{
return default (T);
}
}
Errors:
does not implement inherited abstract member 'A.f<T>()'
no suitable method found to override
I know that the signature must be same, but from my point of view I see no reason what could possibly be wrong that this is forbidden.
Also I know that another solution is to make A generic, rather than its method, but it is not suitable for me for some reason.
This is not possible because those methods have different signatures. A.f is generic method and B.f is not (it merely uses class generic argument).
You can see this form caller perspective:
A variableA = new A();
variableA.f<int>();
B<int> variableB = new B<int>();
variableB.f();
B does not fulfil the contract of A.
A allows f to be called with any type parameter to return that type. B doesn't allow f to be called with a type parameter, and just returns the type of B's type parameter.
For example, say you had a B<int> and cast it to an A (which should be possible as it inherits from it). Then you called f<bool>() on it (which should be possible as it's an A). What then? The underlying B<int> doesn't have a method to call.
B b = new B<int>();
// This is legal as B inherits from A
A a = b;
// This is a legal call, but how does b handle it?
bool result = a.f<bool>();
In the case of your code
abstract class A
{
public abstract T f<T>();
}
class B<T> : A
{
public override T f()
{
return default (T);
}
}
what do you expect to be called in the below code
public void Foo(A myObj) {
myObj.f<DateTime>();
}
Foo(new B<int>());
There's no implementation for that method though the type contract (the abstract class A) clearly states that you need an implementation. So you can either implement or change the contract to use a type argument at the class level
abstract class A<T>
{
public abstract T f();
}
class B<T> : A<T>
{
public override T f()
{
return default (T);
}
}
does compile however it also limits f of course
Probably this is what you intend to do:
abstract class A
{
public abstract T f<T>();
}
class B<U> : A
{
public override T f<T>() //also needs to have a generic type parameter
{
throw new NotImplementedException();
}
public U f()
{
return f<U>();
}
}
The generic method type parameter and the generic class type parameter (here T and U) have no straightforward connection, i.e. T is not restricted to be U (or something) in the base class and you cannot change this restriction in the derived class.
abstract class A
{
public abstract T f<T>();
}
class B<T> : A
{
public override T f<T>()
{
return default (T);
}
}
are the two methods in the class "Confused" below the same?
class MyClass
{
public override string ToString()
{
return "I am confused now";
}
}
class Confused
{
public MyClass GetMyClass()
{
return new MyClass();
}
public T GetMyClass<T>() where T : MyClass, new()
{
return System.Activator.CreateInstance<T>();
}
}
class Program
{
static void Main()
{
Confused c = new Confused();
System.Console.WriteLine(c.GetMyClass());
System.Console.WriteLine(c.GetMyClass<MyClass>());
}
}
They produce different IL, but is there any reason to write the generic version other than the 'straight up' version other than to confuse the heck out of collegues :)
If you write the generic version, you can instantiate and return derived classes:
where T : MyClass
Also, with the generic version you don't need the activation code:
return new T();
This is because you have specified:
where T : new()
The generic constraint enforcing a public parameterless constructor.
Sure there's a difference. Let's say you have a second class deriving from MyClass:
class MyClass2 : MyClass { }
Then you can do
MyClass2 myClass2 = confused.GetMyClass<MyClass2>();
You can't do that with the other function.
MyClass could be a base class (or an interface IMyClass). The generic version with the constraint says you want this function to work for any class derived from (or implementing) a common base or interface and to return the result as that derived class, not as the base.
class MyClass { }
class MySpecializedClass : MyClass { }
// etc.
There is a very big difference:
The non generic version can only return instances of type MyClass, whereas the generic version can return instances of type MyClass and all classes derived from MyClass!
No. They are not the same. The first will only ever construct a MyClass object, and the second will construct any object that is a MyClass or a descendent of MyClass, based on the type parameter.
They would give the same result ONLY if you called .GetMyClass<MyClass>(). However, I presume the extra method has been created to allow for creation of other classes? If not, then they're the same, so one's redundant (and I'd get rid of the generic version as has overhead inside the assembly).
Are they being used differently?
They are not the same. The generic allows inherited classes to be built as well like this:
class MyClass
{
public override string ToString()
{
return "I am confused now";
}
}
class InheritedClass : MyClass
{
}
class Confused
{
public MyClass GetMyClass()
{
return new MyClass();
}
public T GetMyClass<T>() where T : MyClass, new()
{
return System.Activator.CreateInstance<T>();
}
}
class Program
{
static void Main()
{
Confused c = new Confused();
System.Console.WriteLine(c.GetMyClass());
System.Console.WriteLine(c.GetMyClass<MyClass>());
System.Console.WriteLine(c.GetMyClass<InheritedClass>());
}
}
I'm not quite sure, but Generics are a runtime feature in .NET. Therefore, the non-generic method isn't equivalent to the generic one, even though it is used equivalently. As they're public, this can't be optimized away.