如何允许C#方法的泛型类型参数接受null参数?

时间:2011-04-10 14:43:02

标签: c# generics .net-4.0

private static Matcher<T> EqualTo<T>(T item)
{
    return new IsEqual<T>(item);
}

如何修改上述方法定义,以使以下内容有效/允许。

EqualTo("abc");
EqualTo(4);
EqualTo(null); // doesn't compile. EqualTo<string>(null) does

尝试移植某些Java代码,null似乎是T参数的可接受值。


更新
谢谢:所有答案 - 特别是Eamon和Jason。我不希望方法调用打扰类型推断。以下重载修复了它。

    private static Matcher<object> EqualTo(object item)
    {
        return EqualTo<object>(item);
    }  

实际上,上述问题是一个更大难题的一部分。最终目标是以下工作。

        this.AssertThat(null, EqualTo(null));
        this.AssertThat(null, Not(EqualTo("hi")));
        this.AssertThat("hi", Not(EqualTo(null)));

应用相同的修复程序.. RFC 。 (忽略丑陋的扩展方法部分 - 这是另一个问题。想要在没有继承的情况下在所有测试装置中使用这些方法。)

public static void AssertThat<T>(this object testFixture, object actual, Matcher<T> matcher, string message = "")
{
  AssertThat(anyObject, (T)actual, matcher, message);
}

public static void AssertThat<T, TSuper>(this object testFixture, T actual, Matcher<TSuper> matcher, string message = "") where T : TSuper
{
  ... check and assert

5 个答案:

答案 0 :(得分:11)

考虑以下方法:

public bool IsNullString<T>(T item) {
    return typeof(T) == typeof(string) && item == null;
}

是的,这是一种可鄙的愚蠢方法,使用泛型在这里毫无意义,但你马上就会明白这一点。

现在考虑

bool first = IsNullString<string>(null);
bool second = IsNullString<Foo>(null);

bool third = IsNullString(null);

在第一个和第二个中,编译器可以清楚地区分T的类型(不需要推断)。第三,编译器如何推断T是什么?特别是,它无法区分T == stringT == Foo,或任何其他类型。因此,编译器必须给你一个编译时错误。

如果你想解决这个问题,你需要投射null

EqualTo((object)null);

或明确说明类型

EqualTo<object>(null)

或定义重载

private static Matcher<object> EqualTo(object item) {
    return new IsEqual<object>(item);
}

答案 1 :(得分:2)

如果没有明确指定T或进行强制转换,则无法实现。泛型是编译时构造,因此如果编译器无法在编译时弄清楚类型,那么它将无法编译(正如您所看到的那样)。

答案 2 :(得分:2)

由于您无法完成您想要做的事情,如何定义EqualTo(object)重载方法?这应该允许您需要的语法。

答案 3 :(得分:2)

您可以使用以下语法解决此限制:

EqualTo("abc");
EqualTo(4);
EqualTo(default(object));
//equivalently:
EqualTo((object)null);

default(T)T类型字段的值,如果未设置。对于引用类型,它是null,对于值类型,它本质上是用零字节填充的内存(...对于不同类型可能意味着不同的东西,但通常意味着某个版本为零)。

我现在尝试避免代码中到处都是null。它也阻碍了其他地方的类型推断,例如var声明字段和三元运算符。例如,myArray==null ? default(int?) : myArray.Length可以,但myArray==null ? null : myArray.Length将无法编译。

答案 4 :(得分:0)

也许实现一个非泛型的EqualTo,它将Object作为参数类型,可以解决重写这些代码行的问题。