2012-02-28 2 views
3

Я пытаюсь использовать дженерики со специализацией. См. Код ниже. То, что я хочу сделать, - заставить механизм выполнения понять, что специализация функции доступна на основе типа, и она должна использовать это вместо универсального метода. Возможно ли без использования ключевого слова dynamic?C#: Generics, Polymorphism and Specialization

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

Если нет какой-либо способ добиться того, чего я хочу без использования ключевого слова динамического, может ли быть элегантный способ достижения литья для конкретного типа без огромного Enum \ флаг \ включение случае?

EDIT - ВОЗМОЖНО один из способов достижения этой цели Я хотел опубликовать это как ответ, но это на самом деле не на основе полиморфизма или перегрузки так решили поставить в качестве редактирования вместо этого. Дайте мне знать, если это имеет смысл.

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)" 
    } 

Спасибо заранее, -Neel.

ответ

3

Я не верю, что это можно сделать. Он просто не является частью механизма отправки времени выполнения, который поддерживает CLR. Вы могли бы написать это, конечно:

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)"); 
} 

... но это не очень приятно.

+0

Спасибо. Вы правы - я ищу полиморфизм на основе типичного типа, а не параметра типа. Хорошая вещь - динамика, похоже, работает так, как ожидалось, плохая вещь, я не могу перейти на .NET 4.0 прямо сейчас. –

0

Вы можете достичь этого с явной реализацией IUnknown<DerivedT>. Однако я не уверен, что это то, что вы ищете.

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"); 
    } 
} 
+0

спасибо, но я искал что-то, что не связано с приведением типов. Проблема в том, что если у меня есть десять разных типов, хранящихся в списке, мне нужно будет иметь случай переключения или что-то похожее –

0

Я хотел бы предложить определение общего статический класса NamePrinter<T>, с Action<T> называется PrintName, который первоначально указует на закрытый метод, который проверяет T является ли особым типом и либо устанавливает PrintName либо специализированную версию, или не -специализированная версия (неспециализированная версия может при необходимости генерировать исключение), а затем вызывает делегата PrintName. Если это делается, то при первом вызове NamePrinter<T>.PrintName(T param) для любого конкретного T код должен будет проверить тип T, чтобы определить, какой «реальный» метод использовать, но будущие вызовы будут отправляться непосредственно в правильную процедуру.