是否可以在 C# 泛型方法中定义 "not Nullable<T>" 约束?

Is it possible to define a "not Nullable<T>" constraint in a C# generic method?

在 C# 中,Nullable<T> 类型不满足 where struct 泛型约束(据我所知,这在技术上是一个结构)。这可用于指定泛型参数必须是不可为 null 的值类型:

T DoSomething<T>() where T : struct
{
   //... 
} 
DoSomething<int?>(); //not ok
DoSomething<int>();  //ok

当然,Nullable<T>也不满足引用类型whereclass约束:

T DoSomething<T>() where T : class
{
   //...
} 
DoSomething<int?>(); //not ok
DoSomething<Foo>();  //ok

是否可以定义约束,例如它必须是引用类型或值类型而不是可空值类型?

像这样:

void DoSomething<T>() where T : class, struct //wont compile!
{    
   //...   
} 
DoSomething<int?>(); //not ok
DoSomething<int>();  //ok
DoSomething<Foo>();  //ok

不,在声明方面是不可能的。它是 structclass。 但是,您可以在 运行 时检查 typeof(T) 以确保 TNullable<T2>

Type type = typeof(T);
if(Nullable.GetUnderlyingType(type) == null)
    throw new Exception();

如评论中所述,您可以使用重载 参数(可以是可选的)来执行此操作。我 blogged about this 刚才,但在你的情况下你想要:

public class ClassConstraint<T> where T : class
{
}

public class SomeClass<TViewModel>
{
    public void Add<TValue>(Func<TViewModel, TValue> expression,
                            ClassConstraint<TValue> ignored = null)
        where TValue : class
    {
        AddImpl(expression);
    }

    public void Add<TValue>(Func<TViewModel, TValue> expression,
                            Nullable<TValue> ignored = null)
        where TValue : struct
    {
        AddImpl(expression);
    }

    // No constraints
    private void AddImpl<TValue>(Func<TViewModel, TValue> expression)
    {
        ...
    }
}

它很丑,但它有效:

var z = new SomeClass<string>();
z.Add(x => x.Length);        // Valid (non-nullable value type)
z.Add(x => x);               // Valid (reference type)
z.Add(x => new DateTime?()); // Invalid (nullable value type)