使用值类型传递时,编译器不会调用适当的泛型重载

naw*_*fal 9 c# generics overloading type-inference value-type

我有这样的公共功能:

public static T Get<T>(this Mango m, T defaultValue = default(T)) where T : class
{
    //do something; return something;
}

public static T? Get<T>(this Mango m, T? defaultValue = default(T?)) where T : struct
{
    //do something; return something;
}
Run Code Online (Sandbox Code Playgroud)

基本上我想单独处理引用类型和可空类型.它汇编; 直到我呼吁价值类型.对于参考类型,它编译.

mango.Get<string>(); // compiles..
mango.Get(""); // compiles..

mango.Get<int>(); // The type 'int' must be a reference type in order to use it as 
                  // parameter 'T' in the generic type or method Get<T>(Mango, T)
//also            // The call is ambiguous between the following methods or properties: 
                  // Get<int>(Mango, int) and Get<int>(Mango, int?)
Run Code Online (Sandbox Code Playgroud)

真正含糊不清的是什么?如果Tint,它不能适当地调用结构超载?也:

mango.Get<int>(0);  // The type 'int' must be a reference type in order to use it as 
                    // parameter 'T' in the generic type or method Get<T>(Mango, T)
Run Code Online (Sandbox Code Playgroud)

为什么编译器只检测引用类型重载?我尝试过两个独立的重载:

public static T Get<T>(this Mango m) where T : class
{
    return default(T);
}

public static T? Get<T>(this Mango m) where T : struct
{
    return default(T);
}

public static T Get<T>(this Mango m, T def) where T : class
{
    return default(T);
}

public static T? Get<T>(this Mango m, T? def) where T : struct
{
    return default(T);
}
Run Code Online (Sandbox Code Playgroud)

问题依然存在.显然,前两种方法不在这里编译,因为重载不仅仅是基于约束.

我尝试通过删除class约束重载并保持受约束的重载struct,如下所示:

public static T? Get<T>(this Mango m, T? defaultValue = default(T?)) where T : struct
{
    //do something; return something;
}

mango.Get<int>(); // voila compiles!
mango.Get<int>(0); // no problem at all..
// but now I can't have mango.Get<string>() for instance :(
Run Code Online (Sandbox Code Playgroud)

我只剩下重命名这两个功能吗?我认为拥有一个统一的名称是合适的,这样调用者就不必担心实现细节,而只需要调用Get任何类型.

更新:如果我必须避免可选参数,Marc的解决方案不起作用.

mango.Get<int>(); // still wouldnt work!!
Run Code Online (Sandbox Code Playgroud)

但是有更多的魔力:( :(

public static bool IsIt<T>(this T? obj) where T : struct
{
    return who knows;
}

public static bool IsIt<T>(this T obj) where T : class
{
    return perhaps;
}
Run Code Online (Sandbox Code Playgroud)

无论如何,我期待相同的编译器错误(根据我)来惹恼我.但这次不行.

Guid? g = null;
g.IsIt(); //just fine, and calls the struct constrained overload
"abcd".IsIt(); //just fine, and calls the class constrained overload
Run Code Online (Sandbox Code Playgroud)

因此,如果在Marc所说的约束检查之前出现过载分辨率,那么我这次也不应该得到相同的错误吗?但不是.为什么会这样?这到底是怎么回事?:X

Mar*_*ell 6

超载解决后进行约束检查,IIRC; 重载决议似乎更喜欢第一个版本.但是你可以强迫它使用另一个:

mango.Get<int>((int?)0);
Run Code Online (Sandbox Code Playgroud)

甚至:

mango.Get((int?)0);
Run Code Online (Sandbox Code Playgroud)

就个人而言,我可能只是更改名称以避免歧义.