132

だから私はこのクラスを持っています:

public class Foo<T> where T : ???
{
    private T item;

    public bool IsNull()
    {
        return item == null;
    }

}

今、すべてを型パラメーターとして使用できる型制約を探していますnull。これは、すべてのNullable( T?) 型だけでなく、すべての参照型を意味します。

Foo<String> ... = ...
Foo<int?> ... = ...

できるはずです。

class型制約として使用すると、参照型のみを使用できます。

追加情報: 私はパイプとフィルターのアプリケーションを作成しnullており、パイプラインに渡される最後のアイテムとして参照を使用して、すべてのフィルターを適切にシャットダウンしたり、クリーンアップを実行したりしたいと考えています...

4

8 に答える 8

23

ジェネリックでORに相当するものを実装する方法がわかりません。ただし、null 許容型に null を作成し、構造体に 0 値を作成するために、デフォルトのキーワードを使用することを提案できます。

public class Foo<T>
{
    private T item;

    public bool IsNullOrDefault()
    {
        return Equals(item, default(T));
    }
}

Nullable のバージョンを実装することもできます。

class MyNullable<T> where T : struct
{
    public T Value { get; set; }

    public static implicit operator T(MyNullable<T> value)
    {
        return value != null ? value.Value : default(T);
    }

    public static implicit operator MyNullable<T>(T value)
    {
        return new MyNullable<T> { Value = value };
    }
}

class Foo<T> where T : class
{
    public T Item { get; set; }

    public bool IsNull()
    {
        return Item == null;
    }
}

例:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(new Foo<MyNullable<int>>().IsNull()); // true
        Console.WriteLine(new Foo<MyNullable<int>> {Item = 3}.IsNull()); // false
        Console.WriteLine(new Foo<object>().IsNull()); // true
        Console.WriteLine(new Foo<object> {Item = new object()}.IsNull()); // false

        var foo5 = new Foo<MyNullable<int>>();
        int integer = foo5.Item;
        Console.WriteLine(integer); // 0

        var foo6 = new Foo<MyNullable<double>>();
        double real = foo6.Item;
        Console.WriteLine(real); // 0

        var foo7 = new Foo<MyNullable<double>>();
        foo7.Item = null;
        Console.WriteLine(foo7.Item); // 0
        Console.WriteLine(foo7.IsNull()); // true
        foo7.Item = 3.5;
        Console.WriteLine(foo7.Item); // 3.5
        Console.WriteLine(foo7.IsNull()); // false

        // var foo5 = new Foo<int>(); // Not compile
    }
}
于 2013-11-07T08:55:38.777 に答える
9

前述のように、コンパイル時にチェックすることはできません。.NET の一般的な制約は大幅に不足しており、ほとんどのシナリオをサポートしていません。

ただし、これは実行時チェックのより良い解決策であると考えています。どちらも定数であるため、JIT コンパイル時に最適化できます。

public class SomeClass<T>
{
    public SomeClass()
    {
        // JIT-compile time check, so it doesn't even have to evaluate.
        if (default(T) != null)
            throw new InvalidOperationException("SomeClass<T> requires T to be a nullable type.");

        T variable;
        // This still won't compile
        // variable = null;
        // but because you know it's a nullable type, this works just fine
        variable = default(T);
    }
}
于 2015-03-14T16:27:35.900 に答える
3

私が使う

public class Foo<T> where T: struct
{
    private T? item;
}
于 2016-03-16T10:04:57.367 に答える
3

そのような型制約は不可能です。型制約のドキュメントによると、null 許容型と参照型の両方をキャプチャする制約はありません。制約は組み合わせでのみ組み合わせることができるため、組み合わせによってそのような制約を作成する方法はありません。

ただし、必要に応じて、制約のない型パラメーターにフォールバックできます。これは、常に == null をチェックできるためです。型が値型の場合、チェックは常に false と評価されます。次に、セマンティクスが適切である限り、R# の警告「Possible compare of value type with null」が表示される可能性がありますが、これは重要ではありません。

代わりに使用することができます

object.Equals(value, default(T))

T : クラスが常に null である default(T) であるため、null チェックの代わりに。ただし、これは、null 非許容値が明示的に設定されていないか、デフォルト値に設定されているだけかを区別できないことを意味します。

于 2013-11-07T08:56:22.233 に答える