为什么不发生超载?

the*_*row 5 .net c# generics overloading

我有以下课程:

class CrmToRealTypeConverter : IConverter
{
    #region IConverter Members

    public object Convert<T>(T obj)
    {
        return Convert(obj);
    }

    #endregion

    private DateTime? Convert(CrmDateTime obj)
    {
        return obj.IsNull == false ? (DateTime?)obj.UserTime : null;
    }

    private int? Convert(CrmNumber obj)
    {
        return obj.IsNull == false ? (int?)obj.Value : null;
    }

    private decimal? Convert(CrmDecimal obj)
    {
        return obj.IsNull == false ? (decimal?)obj.Value : null;
    }

    private double? Convert(CrmDouble obj)
    {
        return obj.IsNull == false ? (double?)obj.Value : null;
    }

    private float? Convert(CrmFloat obj)
    {
        return obj.IsNull == false ? (float?)obj.Value : null;
    }

    private decimal? Convert(CrmMoney obj)
    {
        return obj.IsNull == false ? (decimal?)obj.Value : null;
    }

    private bool? Convert(CrmBoolean obj)
    {
        return obj.IsNull == false ? (bool?)obj.Value : null;
    }
}
Run Code Online (Sandbox Code Playgroud)

我试图使用concreate类型专门化Convert方法.
目前它只是递归循环,Convert<T>()直到发生堆栈溢出.

Ani*_*Ani 2

后期绑定并不像您想象的那样发生;Convert(obj)编译器将方法中的调用绑定public object Convert<T>(T obj)同一个方法(递归调用)。您似乎期望的行为是 CLR 将动态选择最合适的重载来在运行时执行,但事实并非如此。尝试这样的事情:

public object Convert<T>(T obj)
{
   if (obj == null)
       throw new ArgumentNullException("obj");

    var cdt = obj as CrmDateTime;   
    if (cdt != null)
        return Convert(cdt); // bound at compile-time to DateTime? Convert(CrmDateTime)

    var cn = obj as CrmNumber;    
    if (cn != null)
        return Convert(cn); // bound at compile-time to int? Convert(CrmNumber)

    // ...    

    throw new NotSupportedException("Cannot convert " + obj.GetType());
}
Run Code Online (Sandbox Code Playgroud)

如果您愿意,可以在此处使用反射。这样的解决方案看起来像:

// Making the method generic doesn't really help
public object Convert(object obj) 
{
   if (obj == null)
       throw new ArgumentNullException("obj");

    // Target method is always a private, instance method
    var bFlags = BindingFlags.Instance | BindingFlags.NonPublic;

    // ..which takes a parameter of the obj's type.      
    var parameterTypes = new[] { obj.GetType() };

    // Get a MethodInfo instance that represents the correct overload
    var method = typeof(CrmToRealTypeConverter)
                 .GetMethod("Convert", bFlags, null, parameterTypes, null);

    if (method == null)
        throw new NotSupportedException("Cannot convert " + obj.GetType());

    // Invoke the method with the forwarded argument
    return method.Invoke(this, new object[] { obj });
}  
Run Code Online (Sandbox Code Playgroud)