C# generic type constraint for everything nullable

后端 未结 8 2078
无人共我
无人共我 2020-12-09 14:11

So I have this class:

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

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

}
         


        
8条回答
  •  伪装坚强ぢ
    2020-12-09 14:46

    I ran into this issue for a simpler case of wanting a generic static method that could take anything "nullable" (either reference types or Nullables), which brought me to this question with no satisfactory solution. So I came up with my own solution which was relatively easier to solve than the OP's stated question by simply having two overloaded methods, one that takes a T and has the constraint where T : class and another that takes a T? and has where T : struct .

    I then realized, that solution can also be applied to this problem to create a solution that is checkable at compile time by making the constructor private (or protected) and using a static factory method:

        //this class is to avoid having to supply generic type arguments 
        //to the static factory call (see CA1000)
        public static class Foo
        {
            public static Foo Create(TFoo value)
                where TFoo : class
            {
                return Foo.Create(value);
            }
    
            public static Foo Create(TFoo? value)
                where TFoo : struct
            {
                return Foo.Create(value);
            }
        }
    
        public class Foo
        {
            private T item;
    
            private Foo(T value)
            {
                item = value;
            }
    
            public bool IsNull()
            {
                return item == null;
            }
    
            internal static Foo Create(TFoo value)
                where TFoo : class
            {
                return new Foo(value);
            }
    
            internal static Foo Create(TFoo? value)
                where TFoo : struct
            {
                return new Foo(value);
            }
        }
    

    Now we can use it like this:

            var foo1 = new Foo(1); //does not compile
            var foo2 = Foo.Create(2); //does not compile
            var foo3 = Foo.Create(""); //compiles
            var foo4 = Foo.Create(new object()); //compiles
            var foo5 = Foo.Create((int?)5); //compiles
    

    If you want a parameterless constructor, you won't get the nicety of overloading, but you can still do something like this:

        public static class Foo
        {
            public static Foo Create()
                where TFoo : class
            {
                return Foo.Create();
            }
    
            public static Foo CreateNullable()
                where TFoo : struct
            {
                return Foo.CreateNullable();
            }
        }
    
        public class Foo
        {
            private T item;
    
            private Foo()
            {
            }
    
            public bool IsNull()
            {
                return item == null;
            }
    
            internal static Foo Create()
                where TFoo : class
            {
                return new Foo();
            }
    
            internal static Foo CreateNullable()
                where TFoo : struct
            {
                return new Foo();
            }
        }
    

    And use it like this:

            var foo1 = new Foo(); //does not compile
            var foo2 = Foo.Create(); //does not compile
            var foo3 = Foo.Create(); //compiles
            var foo4 = Foo.Create(); //compiles
            var foo5 = Foo.CreateNullable(); //compiles
    
    
    

    There are few disadvantages to this solution, one is that you may prefer using 'new' to construct objects. Another is that you won't be able to use Foo as a generic type argument for a type constraint of something like: where TFoo: new(). Finally is the bit of extra code you need here which would increase especially if you need multiple overloaded constructors.

    提交回复
    热议问题