2012-02-28 10 views
3

私は専門化されたジェネリックを使用しようとしています。以下のコードを参照してください。私がしたいのは、関数の特殊化が型に基づいて利用可能であり、汎用メソッドの代わりにその関数を使用する必要があることをランタイムエンジンが理解できるようにすることです。可能であれば動的キーワードを使用しないでくださいか?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

巨大な列挙\フラグなしのコンクリート型にキャスト達成するための任意のエレガントな方法があるかもしれません、私はdynamicキーワードを使用せずに欲しいものを達成するために、どのような方法が存在しない場合には\スイッチケース?

EDIT - 私は答えとしてこれを投稿したいTHIS を達成する可能性ONE WAYが、これは本当に多型または過負荷に基づいていないので代わりに編集として置くことにしました。これが理にかなっているかどうかを教えてください。

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

ありがとうございます。 - ニッケル。

答えて

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

ありがとう、しかし私は型キャスティングを伴わない何かを探していました。その問題は、リストに10種類の異なるタイプが格納されている場合、スイッチのケースなどが必要になります –

0

私が最初にTが特殊なタイプであるかどうかをチェックし、いずれかの特殊なバージョンまたは非いずれかにPrintNameを設定し、民間の方法を指すPrintNameと呼ばAction<T>とジェネリック静的クラスNamePrinter<T>を、定義することをお勧め(特殊化されていないバージョンでは必要に応じて例外がスローされる可能性があります)、PrintNameデリゲートを呼び出します。その場合、最初にTのコードをNamePrinter<T>.PrintName(T param)と呼び出すときに、使用する「実際の」方法を決定するためにコードTを検査する必要がありますが、将来の呼び出しは適切なルーチンに直接送られます。