所以我有这样的课:
public class Foo<T> where T : ???
{
private T item;
public bool IsNull()
{
return item == null;
}
}
现在我正在寻找一个类型约束,它允许我使用所有可以是null
的类型参数。这意味着所有引用类型,以及所有Nullable
(T?
)类型:
Foo<String> ... = ...
Foo<int?> ... = ...
应该是可能的。
使用class
作为类型约束只允许我使用引用类型。
附加信息:我正在编写一个pipes and filters应用程序,并希望使用null
引用作为传递到管道中的最后一项,这样每个过滤器都可以很好地关闭,进行清理,等等。。。
我遇到这个问题是为了一个更简单的情况,即想要一个通用的静态方法,它可以接受任何“可为空”(引用类型或可为空)的内容,这让我无法找到满意的解决方案。因此,我提出了自己的解决方案,它比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
我不知道如何实现等价于或泛型。但是,我可以建议使用默认关键字,以便为可空类型创建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
}
}
如果您愿意在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。同样,