我正在设计一个实体类,它有一个名为"documentYear"的字段,可能有无符号整数值,如1999,2006等.同时,这个字段也可能是"未知",也就是说,不确定文档是哪一年创建.
因此,C#中的可空int类型将非常适合.但是,Java没有像C#那样可以为空的特性.
我有两个选择,但我不喜欢它们:
java.lang.Integer而不是原始类型int;有没有人有更好的选择或想法?
更新:我的实体类将有数万个实例; 因此,java.lang.Integer的开销可能对系统的整体性能来说太重了.
这可能是关于可空类型的问题的后续问题.
哪些可以为空的值类型(int?...)存储在内存中?首先,我认为它很清楚,Nullable<T>结构和那些是值类型.然后我找到了Jon Skeet的文章" Memory in .NET ",其中说:
请注意,值类型变量永远不能具有null值 - 它没有任何意义,因为null是引用类型概念,意味着"此引用类型变量的值根本不是对任何对象的引用" .
阅读本声明后,我有点困惑.所以,让我说我有int? a = null;.由于int通常是值类型,是它在某种程度上内部存储结构Nullable<T>在堆栈(我用"正常",因为我不知道值类型会发生什么,当它变成可为空)?或者其他任何事情发生在这里 - 也许在堆中?
我今天早些时候发生的事情让我摸不着头脑.
Nullable<T>可以为任何类型的变量赋值null.例如:
int? i = null;
Run Code Online (Sandbox Code Playgroud)
起初,我看不出如何做到这一点是可能的,而不以某种方式从定义的隐式转换object到Nullable<T>:
public static implicit operator Nullable<T>(object box);
Run Code Online (Sandbox Code Playgroud)
但是上面的运算符显然不存在,就好像它确实如此,那么下面的内容也必须是合法的,至少在编译时(它不是):
int? i = new object();
Run Code Online (Sandbox Code Playgroud)
然后我意识到,也许Nullable<T>类型可以定义一个隐式转换为一些永远无法实例化的任意引用类型,如下所示:
public abstract class DummyBox
{
private DummyBox()
{ }
}
public struct Nullable<T> where T : struct
{
public static implicit operator Nullable<T>(DummyBox box)
{
if (box == null)
{
return new Nullable<T>();
}
// This should never be possible, as a DummyBox cannot be instantiated.
throw new InvalidCastException();
}
} …Run Code Online (Sandbox Code Playgroud) 可能重复:
C++中的Nullable值
在C++中表示可空成员的最佳方法是什么?
在C#中,我们可以使用Nullable<T>类型.非常需要这样的数据类型,因为并非所有数据都具有有意义的价值.这是一个非常重要的数据类型,@ Jon Skeet花了整整一章,跨越了27页,仅Nullable<T>在他的优秀着作C#Depth中进行了描述.
一个简单的例子可以是一个Person类1,定义为:
struct Person
{
std::string Name;
DateTime Birth;
DateTime Death;
//...
};
Run Code Online (Sandbox Code Playgroud)
由于一个人总是有生日,所以Birth上述班级的成员总会有一些有意义的价值.但是怎么样Death?如果这个人还活着,它应该有什么价值呢?在C#中,此成员可以声明为Nullable<DataTime>2,null如果此人活着,则可以将其分配.
在C++中,解决这个问题的最佳方法是什么?截至目前,我只考虑了一个解决方案:将成员声明为指针:
DataTime *Death;
Run Code Online (Sandbox Code Playgroud)
现在它的价值可以是nullptr人活着的时候.但它强迫使用new死人,因为它会有一些有效的价值.它反过来意味着不能依赖编译器生成的默认复制语义代码.程序员必须编写复制构造函数,复制赋值,析构函数遵循三条规则(C++ 03),或者在C++ 11中规则,五条规则.
那么,除了制作指针之外,我们还有更好,更优雅的解决方案吗?
其他示例包括关系数据库表,因为在许多DBMS中,列可以为空.
这也有一个简写.人们可以写DataTime?这正是因为相同Nullable<DateTime>.
我在Nullable隐式转换之间的交互中遇到了一些有趣的行为.我发现从值类型提供引用类型的隐式转换,它允许Nullable在我反对期望编译错误时将类型传递给需要引用类型的函数.以下代码演示了这一点:
static void Main(string[] args)
{
PrintCatAge(new Cat(13));
PrintCatAge(12);
int? cat = null;
PrintCatAge(cat);
}
private static void PrintCatAge(Cat cat)
{
if (cat == null)
System.Console.WriteLine("What cat?");
else
System.Console.WriteLine("The cat's age is {0} years", cat.Age);
}
class Cat
{
public int Age { get; set; }
public Cat(int age)
{
Age = age;
}
public static implicit operator Cat(int i)
{
System.Console.WriteLine("Implicit conversion from " + i);
return new Cat(i);
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
The cat's age …Run Code Online (Sandbox Code Playgroud) 例如,如果我有以下数据类:
data class Data(
val name: String = "",
val number: Long = 0
)
Run Code Online (Sandbox Code Playgroud)
和可以返回的功能null:
fun newName(): String? {}
fun newNumber(): Long? {}
Run Code Online (Sandbox Code Playgroud)
我知道如果不是,我可以使用以下代码来使用函数的值null:
val newName = newName()
val newNumber = newNumber()
val data = Data(
if (newName != null) newName else "",
if (newNumber != null) newNumber else 0
)
Run Code Online (Sandbox Code Playgroud)
但有没有办法在值为时使用Data类的构造函数中指定的默认值null?
我在文档中找不到任何内容,但我希望这样的东西能够工作:
val data = Data(newName()?, newNumber()?)
Run Code Online (Sandbox Code Playgroud)
但那不编译.
以下Kotlin代码:
val x = null + null
Run Code Online (Sandbox Code Playgroud)
结果x是类型String,这是正确的,根据文档String.plus:
将此字符串与给定[other]对象的字符串表示形式连接起来.如果receiver或[other]对象为null,则表示为字符串"null".
但是,我不明白为什么会发生这种情况 - 是否是由于该语言的一些特殊功能?
如果在属性的setter中有这个:
decimal? temp = value as decimal?;
Run Code Online (Sandbox Code Playgroud)
value ="90"
但演员表演后,临时为空 ......
做这个演员的正确方法是什么?
在C#中,default(Nullable<long>)(或default(long?))和default(long)?之间有区别吗?
Long只是一个例子,它可以是任何其他struct类型.
我有一个具有许多Nullable <T>属性的类,我想将其作为属性序列化为XML.这显然是禁忌,因为它们被认为是"复杂类型".所以,我实现了*Specified模式,我在其中创建了一个add*Value和*Specified属性,如下所示:
[XmlIgnore]
public int? Age
{
get { return this.age; }
set { this.age = value; }
}
[XmlAttribute("Age")]
public int AgeValue
{
get { return this.age.Value; }
set { this.age = value; }
}
[XmlIgnore]
public bool AgeValueSpecified
{
get { return this.age.HasValue; }
}
哪个工作正常 - 如果'Age'属性有值,则将其序列化为属性.如果它没有值,则不会序列化.
问题在于,正如我所提到的,我的班级中有很多Nullable-s,这种模式只是让事情变得混乱和无法管理.
我希望有一种方法可以使Nullable更友好的XmlSerializer.或者,如果失败了,那就是创建Nullable替换的方法.
有没有人有任何想法我怎么能这样做?
谢谢.