当前位置: 首页 > 知识库问答 >
问题:

C#所有可为空的内容的泛型类型约束

太叔京
2023-03-14

所以我有这样的课:

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

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

}

现在我正在寻找一个类型约束,它允许我使用所有可以是null的类型参数。这意味着所有引用类型,以及所有NullableT?)类型:

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

应该是可能的。

使用class作为类型约束只允许我使用引用类型。

附加信息:我正在编写一个pipes and filters应用程序,并希望使用null引用作为传递到管道中的最后一项,这样每个过滤器都可以很好地关闭,进行清理,等等。。。

共有3个答案

令狐嘉运
2023-03-14

我遇到这个问题是为了一个更简单的情况,即想要一个通用的静态方法,它可以接受任何“可为空”(引用类型或可为空)的内容,这让我无法找到满意的解决方案。因此,我提出了自己的解决方案,它比OP提出的问题更容易解决,只需使用两个重载方法,一个采用T并具有约束,其中T:class,另一个采用T 和has其中T:struct

然后我意识到,这个解决方案也可以应用于这个问题,通过使构造函数私有(或受保护)并使用静态工厂方法来创建一个在编译时可检查的解决方案:

    //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<TFoo> Create<TFoo>(TFoo value)
            where TFoo : class
        {
            return Foo<TFoo>.Create(value);
        }

        public static Foo<TFoo?> Create<TFoo>(TFoo? value)
            where TFoo : struct
        {
            return Foo<TFoo?>.Create(value);
        }
    }

    public class Foo<T>
    {
        private T item;

        private Foo(T value)
        {
            item = value;
        }

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

        internal static Foo<TFoo> Create<TFoo>(TFoo value)
            where TFoo : class
        {
            return new Foo<TFoo>(value);
        }

        internal static Foo<TFoo?> Create<TFoo>(TFoo? value)
            where TFoo : struct
        {
            return new Foo<TFoo?>(value);
        }
    }

现在我们可以这样使用它:

        var foo1 = new Foo<int>(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

如果你想要一个无参数的构造函数,你不会得到重载的好处,但你仍然可以这样做:

    public static class Foo
    {
        public static Foo<TFoo> Create<TFoo>()
            where TFoo : class
        {
            return Foo<TFoo>.Create<TFoo>();
        }

        public static Foo<TFoo?> CreateNullable<TFoo>()
            where TFoo : struct
        {
            return Foo<TFoo?>.CreateNullable<TFoo>();
        }
    }

    public class Foo<T>
    {
        private T item;

        private Foo()
        {
        }

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

        internal static Foo<TFoo> Create<TFoo>()
            where TFoo : class
        {
            return new Foo<TFoo>();
        }

        internal static Foo<TFoo?> CreateNullable<TFoo>()
            where TFoo : struct
        {
            return new Foo<TFoo?>();
        }
    }

这样使用:

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

这个解决方案有几个缺点,一个是您可能更喜欢使用“new”来构造对象。另一个是你不能使用Foo

吕岳
2023-03-14

我不知道如何实现等价于或泛型。但是,我可以建议使用默认关键字,以便为可空类型创建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
    }
}
丌官嘉勋
2023-03-14

如果您愿意在Foo的构造函数中进行运行时检查,而不是进行编译时检查,那么可以检查该类型是否不是引用或可为null的类型,如果是这样,则抛出异常。

我意识到只有运行时检查可能是不可接受的,但以防万一:

public class Foo<T>
{
    private T item;

    public Foo()
    {
        var type = typeof(T);

        if (Nullable.GetUnderlyingType(type) != null)
            return;

        if (type.IsClass)
            return;

        throw new InvalidOperationException("Type is not nullable or reference type.");
    }

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

然后编译以下代码,但最后一个(foo3)会在构造函数中引发异常:

var foo1 = new Foo<int?>();
Console.WriteLine(foo1.IsNull());

var foo2 = new Foo<string>();
Console.WriteLine(foo2.IsNull());

var foo3= new Foo<int>();  // THROWS
Console.WriteLine(foo3.IsNull());
 类似资料:
  • 泛型的类型约束 swapTwoValues(_:_:)函数和Stack类型可以用于任意类型. 但是, 有时在用于泛型函数的类型和泛型类型上, 强制其遵循特定的类型约束很有用. 类型约束指出一个类型形式参数必须继承自特定类, 或者遵循一个特定的协议、组合协议. 例如, Swift的Dictionary类型在可以用于字典中键的类型上设置了一个限制. 如字典中描述的一样,字典键的类型必须是可哈希的. 也

  • 约束允许将可接受类型参数的域仅限于值类型集(与包括值和引用类型的类型超集相比),但似乎也完全禁止可空类型,尽管在现代版本的C#。 如果我想接受具有附加的空性的值类型,比如

  • 我在typescript中有以下泛型类 但是我不知道为什么得到这个错误Class'(匿名类)'不正确地扩展基类'列'。属性getValue的类型不兼容。类型'(值:数字)=

  • Django 包含一个contenttypes 应用,它可以追踪安装在你的Django 项目里的所有应用,并提供一个高层次的、通用的接口用于与你的模型进行交互。 概述 Contenttypes 的核心应用是ContentType 模型,存在于 django.contrib.contenttypes.models.ContentType。ContentType 的实例表示并存储你的项目当中安装的应用

  • 我定义jackoson序列化器并将其添加到java类中,如下所示: 编译器出现以下错误: 注释的定义为: 如果我从ReportFilterDeserializer中删除泛型attibute,它将通过编译。我不明白编辑为什么抱怨。

  • 主要内容:Null 合并运算符(??)在 C# 1.x 的版本中,一个值类型的变量是不可以被赋值为 null(空值)的,否则会产生异常。而在 C# 2.0 中,新增了一个 nullable 类型,可以使用 nullable 类型定义包含 null 值的数据,例如,您可以在 nullable <Int32>(可为空的 int32 类型)类型的变量中存储 -2147483648 到 2147483647 之间的任何值或者 null。同样,