2012-02-28 39 views
3

我想用專業化的泛型。請參閱下面的代碼。我想要做的是讓運行時引擎明白,功能的專業化是基於類型可用,它應該使用,而不是通用的方法。是否可能沒有使用關鍵字動態C#:泛型,多態和專業化

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

} 

編輯

如果沒有什麼辦法可以達到我想要不使用關鍵字動態的,可以有任何優雅的方式來實現鑄造具體類型而無需龐大的枚舉\標誌\切換情況?

編輯 - 可能是一種方式實現這一 我想張貼此作爲一個答案,但是,這不是真正基於多態性或超載所以決定把作爲一個編輯來代替。讓我知道這是否合理。

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。 – 2012-02-28 18:11:09

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

謝謝,但我正在尋找一些不會涉及類型轉換的東西。問題是如果我有十個不同的類型存儲在列表中,我將需要有切換案例或類似的東西 – 2012-02-28 18:05:35

0

我建議定義一個通用的靜態類NamePrinter<T>,與Action<T>稱爲PrintName,其最初指向,檢查T是否是一種特殊類型的私有方法,要麼設置PrintName到任何一個特殊版本或非 - 專用版本(如果需要,非專業版本可能會引發異常),然後調用PrintName委託。如果有人這樣做,第一次調用NamePrinter<T>.PrintName(T param)對於任何特定的T,代碼將不得不檢查類型T以確定使用哪種「真實」方法,但將來的調用將被直接調度到適當的例程。