Why does not overload occur?

I have the following class:

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

I am trying to specialize the Convert method with concreate types.
Currently, it just recursively recursively passes in Convert<T>()until a stack overflow occurs.

+5
source share
4 answers

Late binding does not happen as you think; the compiler associates a call Convert(obj)in a method public object Convert<T>(T obj)with the same method (recursive call). The behavior you expect is that the CLR will dynamically select the most appropriate overload to execute at runtime, but this does not work. Try something like this:

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

, . :

// 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 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 });
}  
+2

. , , obj, , .

public object Convert(object obj)
{
    if (obj is CrmDateTime)
        return Convert((CrmDateTime)obj);
    if (obj is CrmNumber)
        return Convert((CrmNumber)obj);
    // ...
}
+3

, , .Net Convert, , , . static:

static class CrmToRealTypeConverter : IConverter
{
    #region IConverter Members

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

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

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

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

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

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

    public static bool? Convert(CrmBoolean obj)
    {
        return obj.IsNull == false ? (bool?)obj.Value : null;
    }
}

, , :

CrmDateTime crmDate;
CrmToRealTypeConverter.Convert(crmDate);  // Will call the static DateTime? Convert(CrmDateTime obj) overload    
// or 
CrmNumber crmNum;
CrmToRealTypeConverter.Convert(crmNum);  // Will call the static int? Convert(CrmNumber obj) overload
// and so on...

Edit: :

CrmFloat num;
// ...
Object obj = num;
CrmToRealTypeConverter.Convert(obj);

, , . , :

CrmToRealTypeConverter.Convert((CrmFloat)obj);
+2

, T T = System.Object , , System.Object, . .NET 4 dynamic, T , .

:

class Main {
    static void somefunction(System.String str)
    {
        System.Console.WriteLine("In String overload");
    }
    static void somefunction(System.Object obj)
    {
        System.Console.WriteLine("In Object overload");
    }
    static void somegenericfunction<T>(T object)
    {
        somefunction(object);
    }
    static void dynamicfunction<T>(dynamic T object)
    {
        somefunction(object);
    }
    static void main(System.String[] args)
    {
        somegenericfunction("A string"); // Calls Object overload, even though it a String.
        dynamicfunction("A string"); // Calls String overload
    }
}

, , , .

+1

All Articles