2012-02-28 53 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以确定使用哪种“真实”方法,但将来的调用将被直接调度到适当的例程。