Reputation: 147
I am trying to use generics with specialization. See the code below. What I want to do is make runtime engine understand that specialization of the function is available based on type and it should use that instead of generic method. Is it possible without using keyword dynamic?
public interface IUnknown
{
void PrintName<T>(T someT);
}
public interface IUnknown<DerivedT> : IUnknown
{
//***** I am trying to make runtime engine understand that method below is
//***** specialization of void PrintName<T>(T someT);
void PrintName(DerivedT derivedT);
}
public class SoAndSo<DerivedT> : IUnknown<DerivedT>
{
public void PrintName<T>(T someT) { Console.WriteLine("PrintName<T>(T someT)"); }
public void PrintName(DerivedT derivedT) { Console.WriteLine("PrintName(DerivedT derivedT)"); }
}
public class Test
{
public static void TestIt()
{
List<IUnknown> unknowns = new List<IUnknown>();
unknowns.Add(new SoAndSo<int>());
unknowns.Add(new SoAndSo<string>());
//*** statement below should print "PrintName(DerivedT derivedT)"
unknowns[0].PrintName(10);
//*** statement below should print "PrintName<T>(T someT)"
unknowns[0].PrintName("abc");
//********** code snippet below works exactly as expected ************
dynamic d;
d = unknowns[0];
d.PrintName(10); // <=== prints "PrintName(DerivedT derivedT)"
d.PrintName("abc"); // <=== prints "PrintName<T>(T someT)"
}
}
EDIT
If there isn't any way to achieve what I want without use of keyword dynamic, could there be any elegant way to achieve casting to concrete type without huge enum\flag\switch-case?
EDIT - POSSIBLY ONE WAY OF ACHIEVING THIS I wanted to post this as an answer but this is not really based on polymorphism or overloading so decided to put as an edit instead. Let me know if this makes sense.
public abstract class IUnknown
{
public abstract void PrintName<T>(T someT);
}
public abstract class IUnknown<DerivedT /*, DerivedType*/> : IUnknown //where DerivedType : IUnknown<DerivedT, DerivedType>
{
MethodInfo _method = null;
//***** I am trying to make runtime engine understand that method below is
//***** specialization of void PrintName<T>(T someT);
public override sealed void PrintName<T>(T derivedT)
{
bool isSameType = typeof(T) == typeof(DerivedT);
if (isSameType && null == _method)
{
//str = typeof(DerivedT).FullName;
Type t = GetType();
_method = t.GetMethod("PrintName", BindingFlags.Public |
BindingFlags.Instance,
null,
CallingConventions.Any,
new Type[] { typeof(T) },
null);
}
if (isSameType && null != _method)
{
_method.Invoke(this, new object[] { derivedT });
}
else
{
PrintNameT(derivedT);
}
}
public virtual void PrintNameT<T>(T derivedT)
{
}
public virtual void PrintName(DerivedT derivedT) { Console.WriteLine("PrintName(DerivedT derivedT)"); }
//public static DerivedType _unknownDerivedInstance = default(DerivedType);
}
public class SoAndSo<DerivedT> : IUnknown<DerivedT> //, SoAndSo<DerivedT>>
{
//static SoAndSo() { _unknownDerivedInstance = new SoAndSo<DerivedT>(); }
public override void PrintNameT<T>(T someT) { /*Console.WriteLine("PrintNameT<T>(T someT)");*/ }
public override void PrintName(DerivedT derivedT) { /*Console.WriteLine("PrintName(DerivedT derivedT)");*/ }
}
public static class Test
{
public static void TestIt()
{
List<IUnknown> unknowns = new List<IUnknown>();
unknowns.Add(new SoAndSo<int>());
unknowns.Add(new SoAndSo<float>());
//*** statement below should print "PrintName(DerivedT derivedT)"
unknowns[0].PrintName(10);
//*** statement below should print "PrintName<T>(T someT)"
unknowns[0].PrintName(10.3);
//*** statement below should print "PrintName(DerivedT derivedT)"
unknowns[1].PrintName(10);
//*** statement below should print "PrintName<T>(T someT)"
unknowns[1].PrintName(10.3f);
System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch();
stopWatch.Start();
for (int i = 0; i < 1000000; ++i)
{
unknowns[0].PrintName(10.3);
}
stopWatch.Stop();
System.Diagnostics.Trace.TraceInformation("Milliseconds: {0}", stopWatch.ElapsedMilliseconds);
//********** code snippet below works exactly as expected ************
dynamic d;
d = unknowns[0];
d.PrintName(10); // <=== prints "PrintName(DerivedT derivedT)"
d.PrintName("abc"); // <=== prints "PrintName<T>(T someT)"
}
Thanks in advance, -Neel.
Upvotes: 3
Views: 716
Reputation: 81347
I would suggest defining a generic static class NamePrinter<T>
, with an Action<T>
called PrintName
, which initially points to a private method that checks whether T
is a special type and either sets PrintName
to either a specialized version or the non-specialized version (the non-specialized version could throw an exception if desired), and then invokes the PrintName
delegate. If one does that, the first time one calls NamePrinter<T>.PrintName(T param)
for any particular T
, code will have to inspect type T
to determine which "real" method to use, but future calls will be dispatched directly to the proper routine.
Upvotes: 0
Reputation: 82654
You could achieve this with an explicit implementation of IUnknown<DerivedT>
. However, I'm not sure this is what you are looking for.
public class SoAndSo<DerivedT> : IUnknown<DerivedT>
{
public void PrintName<T>(T someT) { Console.WriteLine("PrintName<T>(T someT)"); }
void IUnknown<DerivedT>.PrintName(DerivedT derivedT) { Console.WriteLine("PrintName(DerivedT derivedT)"); }
}
public class Test
{
public static void TestIt()
{
List<IUnknown> unknowns = new List<IUnknown>();
unknowns.Add(new SoAndSo<int>());
unknowns.Add(new SoAndSo<string>());
//*** statement below should print "PrintName(DerivedT derivedT)"
(unknowns[0] as IUnknown<int>).PrintName(10);
//*** statement below should print "PrintName<T>(T someT)"
unknowns[0].PrintName("abc");
}
}
Upvotes: 0
Reputation: 1504122
I don't believe there's any way of doing this. It's simply not part of the execution-time dispatch mechanism which the CLR supports. You could write this, of course:
public void PrintName<T>(T someT)
{
// This is assuming you want it based on the type of T,
// not the type of the value of someT
if (typeof(DerivedT).IsAssignableFrom(typeof(T))
{
PrintName((DerivedT)(object) someT);
return;
}
Console.WriteLine("PrintName<T>(T someT)");
}
... but that's not terribly pleasant.
Upvotes: 3