c# - C# 泛型可以支持 Class 或 Nullable 吗?
问题描述
在我目前的项目中,我有一Value<T>
堂课。
目前T
可以是任何东西,但我们必须支持Null
值,所以目前我们以两种形式使用它:
Value<string>
或Value<int?>
我可以以任何方式创建一个允许我指定Value<string>
or的 Value 类Value<int>
,但效果是 ValueT
对类有效,但T?
对结构有效?
目标是避免开发人员指定Value<int>
但我们后来遇到问题的情况,因为我们没有正确处理 Null 值。
即,id 像 Compiler 支持以避免错误。
解决方案
我可以以任何方式创建一个
Value
允许我指定Value<string>
or的类Value<int>
,但其效果是 Value 适用T
于类,但适用T?
于结构?
不,因为在泛型类型约束中不能有“或”逻辑。
要在泛型类型约束中实现“或”逻辑,您必须创建两个单独的泛型类,每个类都有自己的泛型类型约束。请注意,这两个类可以继承自一个完全没有类型约束的共享通用基类。
如果该基类型是抽象的,那么您可以确定消费者必须通过派生类的类型约束检查之一(假设没有人添加其他派生类)
改变你的期望而不是试图让它成为你现在想要的方式会更合适。
但我们必须支持
null
价值观
null
如果您使用代替default(T)
,则问题已解决。
- 对于类类型,
default(MyClass)
有效地解析为null
- 对于结构,
default(MyStruct)
返回一个结构,其属性都包含其默认值
default(MyStruct)
是使用“可空性”概念而不必使用文字null
值的常用方法。
一个使用示例:
public class Container<T>
{
private readonly Random _random = new Random();
public T DoSomething(T input)
{
//always returns "nothing"
return default(T);
}
}
public class MyClass
{
public int Value { get; set; }
}
public struct MyStruct
{
public int Value { get; set; }
}
public class Test
{
public bool ContainerReturnsNothing<T>(T input)
{
var container = new Container<T>();
var output = container.DoSomething(input);
return output.Equals(default(T));
}
public void TestAClassAndAStruct()
{
ContainerReturnsNothing(new MyClass() {Value = 1}); // true
ContainerReturnsNothing(new MyStruct() {Value = 1}); // true
}
}
在该TestAClassAndAStruct
方法中,您可以看到无论您使用类还是结构,此通用调用堆栈的工作方式完全相同。
如果将容器更改为return input
; 然后在这两种情况下ContainerReturnsNothing
都会返回false
。
您可能需要注意的一件事是,“无”结构无法与已创建但其属性都具有默认值的结构区分开来。如果一个结构的属性都碰巧具有默认值,在您的情况下是一个有意义的(即不是无)结构值,那么这是一个问题。
这里有一个简单的例子int
,其default(int)
解析为0
. 如果0
是一个有意义的值,那么它就是not nothing,这意味着你不能用它0
来表示虚无。
但是您可以通过添加一个在执行构造函数时强制包含非默认值的属性来解决该问题:
public struct MyStruct
{
public bool IsConstructed { get; } // default false
public int Value { get; }
public MyStruct(int myValue)
{
this.IsConstructed = true;
this.Value = myValue;
}
}
default(MyStruct)
将始终IsConstructed
设置为false
.- 每个实例化的结构都将始终
IsConstructed
设置为true
.
这避免了这个问题,因为它们永远不会彼此相等。换句话说:
var myStruct = new MyStruct(0);
var isNull = myStruct.Equals(default(MyStruct));
isNull
为假,因为myStruct
和分别包含(和)default(MyStruct)
的不同值。IsConstructed
true
false
MyStruct
如果您使用原始示例中的类运行相同的检查,isNull
将是正确的,因为所有属性都匹配,即myStruct
两者default(MyStruct)
都有一个Value
属性设置为0
.
推荐阅读
- python - 如何使用 PySpark 进行特征选择/特征重要性?
- c++ - 逐行读取文本文件 | C++
- asp.net-core - .Net core 3.1 MVC 站点给出 http 403 错误
- python - 如何在python中将IP地址转换为字符串
- scala - 如何使用 keycloak 保护 http4s webapp?
- docker - dockerfile 完成构建后供应商文件夹消失
- php - 如何将产品页面上输入的文本框值显示到结帐和购物车页面
- java - 如何为 Quarkus REST 客户端配置 ObjectMapper
- php - Facebook 入站回复通过 PHP 中的 Nexmo API
- enums - 如何将全局枚举值转换为 Godot 中的字符串?