为什么不会出现超载的情况呢?

发布于 2024-09-28 11:38:52 字数 1159 浏览 6 评论 0原文

我有以下课程:

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

我正在尝试使用 concreate 类型专门化 Convert 方法。
目前它只是在 Convert() 中递归循环,直到发生堆栈溢出。

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 loops recursively in Convert<T>() until a stack overflow occurs.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

不奢求什么 2024-10-05 11:38:52

多态性不适用于方法调用的参数。您可以使用它来检查 obj 的类型,将其转换为特定类型,然后调用适当的重载。

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

Polymorphism doesn't work on arguments to a method call. An approach you can use it to check the type of obj, cast it to the specific type and then call the appropriate overload.

public object Convert(object obj)
{
    if (obj is CrmDateTime)
        return Convert((CrmDateTime)obj);
    if (obj is CrmNumber)
        return Convert((CrmNumber)obj);
    // ...
}
陈年往事 2024-10-05 11:38:52

后期绑定并不像您想象的那样发生;编译器将对公共对象 Convert(T obj) 方法中的 Convert(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());
}

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

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

Late-binding doesn't happen the way you think it does; the compiler binds the call to Convert(obj) in thepublic object Convert<T>(T obj) method to the same method (recursive call). The behaviour you appear to be expecting is that the CLR will dynamically choose the most appropriate overload to execute at run-time, but it doesn't work that way. Try something like this instead:

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

If you prefer, you can use reflection here. Such a solution would look something like:

// 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 });
}  
·深蓝 2024-10-05 11:38:52

您应该遵循的模型是 .Net Convert 类中的模型,您没有理由将构造函数设为泛型,它不会带来任何结果。将转换例程更改为静态方法,并将类本身更改为静态:

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...

编辑
如果执行以下操作:

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

它将不起作用,因为编译器不知道与重载匹配的类型。你必须投射它并且它会起作用:

CrmToRealTypeConverter.Convert((CrmFloat)obj);

The model you should follow is the model in the .Net Convert class, there is no reason for you to make the constructor a generic, it brings nothing to the table. Change the convert routines to static methods and the class itself to 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;
    }
}

Then when you call one of the convert methods the compiler will select the proper overload to call:

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:
If you do the following:

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

it will not work as the compiler doesn't know the type to match the overload. You would have to cast it and it will work:

CrmToRealTypeConverter.Convert((CrmFloat)obj);
假装爱人 2024-10-05 11:38:52

发生这种情况是因为编译器直到运行时才知道 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's a String.
        dynamicfunction("A string"); // Calls String overload
    }
}

请注意,我手头上实际上没有编译器,这可能无法按字面意思进行编译,但足够接近。

This occurs because the compiler doesn't know the generic type of T until runtime and binds the call to T = System.Object at compile-time, and the only function suitable to take a System.Object is that function itself. However, in .NET 4, you can use the dynamic keyword to cause the runtime to select the correct overload dynamically based on T at runtime, which is what you are looking to happen.

Simple example:

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's a String.
        dynamicfunction("A string"); // Calls String overload
    }
}

Note that I don't actually have my compiler on hand and this might not compile literally, but close enough.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文