我需要创建一个类似于此的类:
class GenericClass<T>
{
public T[] Arr {get; }
public GenericClass(int n)
{
Arr = new T[n];
for (int i = 0; i < n; i++)
{
Arr[i] = null;
}
}
}
但是存在编译错误:
CS0403 无法将null转换为类型参数&#39; T&#39;因为它可能是一个不可为空的值类型。考虑使用&#39;默认(T)&#39;代替。
我不想使用default(T)
,因为它可能与正常值相同,但我需要区分。我不知道类型,所以我不能使用最小的价值。我怎么能使用null?
答案 0 :(得分:4)
泛型的东西是他们必须考虑T
字面上任何东西的可能性,包括不能是null
的类型(包括基元和结构的值类型)。为了将通用参数限制为可以为null
的类型,您需要添加class
约束:
class GenericClass<T> where T : class
{
public T[] Arr { get; private set; }
public GenericClass(int n)
{
Arr = new T[n];
for (int i = 0; i < n; i++)
{
Arr[i] = null;
}
}
}
或者,您可能根本不想处理null
。相反,您可以替换
Arr[i] = null;
与
Arr[i] = default(T);
它会正常工作。 default(T)
将为任何可空类型返回null
,并为任何非可空类型返回默认值。 (int
为0,bool
为false等)
编辑:作为另一种选择,您可以使用Nullable
包装器类型在内部表示对象。 C#允许使用?
运算符来简化此语法:
class GenericClass<T>
{
public T?[] Arr { get; private set; }
public GenericClass(int n)
{
Arr = new T?[n];
}
}
顺便说一句,使用这种方法,不需要迭代数组的每个索引并将其设置为null
,因为C#将为您处理。
答案 1 :(得分:3)
你实际上是在这里射击自己。 .NET中的数组自动设置为该类型的默认值,因此只要类型的默认值为null(所有对象和nullables),只需创建数组就足以将所有项设置为null。如果没有多余的代码,您可能永远不会遇到任何问题,具体取决于您尝试使用此类的方式。
如果您尝试允许GenericClass<int>
等案例并让它公开int?
的数组,那么请执行此操作。 where T : struct
强制提供的类型是值类型,从而允许您使用T?
。在这种情况下,您不能将对象类型用于泛型参数。
class GenericClass<T> where T : struct
{
public T?[] Arr { get; }
public GenericClass(int n)
{
Arr = new T?[n];
}
}
如果您正在尝试创建一个既支持对象实例又支持nullables的类,请尝试此操作。这里的问题是你不能创建一个类型约束 - 如果你使用where T : struct
,你就不能使用对象类型;如果你使用where T : class
,你就不能使用nullables。因此,此类型允许使用GenericClass<MyObject>
(按您想要的方式工作),GenericClass<int?>
(按您想要的方式工作)和GenericClass<int>
(不能按您的方式工作),并且不可能使用无论如何你的工作方式)。不幸的是,没有办法定义这种通用来禁止后一种情况。但是,如果您愿意,可以在运行时进行检查。
class GenericClass<T>
{
public T[] Arr { get; }
public GenericClass(int n)
{
Arr = new T[n];
}
}
答案 2 :(得分:2)
如果您知道T
必须是可以为空的类型,例如Nullable<Xyz>
,则可以强制您的用户改为通过Xyz
,并使{内部{1}}(又名Nullable<Xyz>
):
Xyz?
添加到声明中的class GenericClass<T> where T : struct {
public T?[] Arr {get; }
public GenericClass(int n) {
Arr = new T?[n]; // This will create an array of nulls, no need for a loop
}
}
约束将阻止具有非值类型的参数的where T : struct
实例化。例如,尝试生成GenericClass<T>
将导致编译时错误。
答案 3 :(得分:1)
如果它是值类型,您要做的是使用可空类型实例化您的类:
var obj = new GenericClass<int?>();
然后您可以使用default(T)
而不是null而没有问题。您最终会得到一个int?[]
数组,但您不需要显式使用它,因为数组中的每个元素都会在实例化数组时自动获取默认值。