构建一个行为类似于Nullable<;T>;
本文关键字:Nullable gt lt 类似于 一个 构建 | 更新日期: 2023-09-27 18:13:59
我正在尝试构建一个行为类似Nullable<T>
的类,特别是我可以访问Nullable<T>
类的底层值而不必显式调用nullable.Value
的方式。
在以下示例中,行check1
&CCD_ 5都起作用。
Nullable<DateTime> nullable = new DateTime();
bool check1 = nullable >= DateTime.Now; //Works
bool check2 = nullable.Value >= DateTime.Now; //Works
我构建了自己的类TrackedValue
,它可以记住它包装的值是否已更改。我在CCD_ 7的基础上构建了隐式&显式运算符。
Nullable<T>
定义
public struct Nullable<T> where T : struct
{
public Nullable(T value);
public static explicit operator T(T? value);
public static implicit operator T?(T value);
...
}
TrackedValue<T>
定义
public class TrackedValue<T> : IChangeTracking
{
...
T trackedValue;
public T Value
{
get
{
return this.trackedValue;
}
set
{
this.trackedValue = value;
}
}
public static explicit operator T(TrackedValue<T> value)
{
return value.Value;
}
public static implicit operator TrackedValue<T>(T value)
{
return new TrackedValue<T>() { Value = value };
}
}
所以我希望以下内容能起作用,但check3
不会编译,因为:
Argument 1: cannot convert from 'TrackedValue<System.DateTime>' to 'System.DateTime'
TrackedValue<DateTime> trackedValue = new DateTime();
bool check3 = trackedValue >= DateTime.Now; //Does not work
bool check4 = trackedValue.Value >= DateTime.Now; //Works
任何建议都将不胜感激。
这一行特别不起作用,因为它需要implicit
转换,但您将其标记为explicit
。
public class TrackedValue<T> : IChangeTracking
{
T trackedValue;
public T Value
{
get
{
return this.trackedValue;
}
set
{
this.trackedValue = value;
}
}
public static implicit operator T(TrackedValue<T> value)
{
return value.Value;
}
public static implicit operator TrackedValue<T>(T value)
{
return new TrackedValue<T>() { Value = value };
}
}
但很自然,您想要模仿Nullable<T>
模型。那么,为什么Nullable<T> <= T
是隐式工作的,而不是您的呢?我相信它来自于C#编译器本身。Eric Lippert有一个关于如何编译/优化Nullables的优秀博客系列。
据我所知,编译器本身将编写的代码/IL完全更改为不同的指令集。孙在这个系列的第三个作品开始展示这一点。这是因为我相信它通常会处理null的特殊情况。
我不确定你是否可以解决这个问题,但也许最简单的方法是简单地将那里的一个转换运算符标记为implicit
,并希望它不会对TrackedValue<T>
和Nullable<T>
之间的一致性造成任何重大问题。
编辑:其中一个不一致的项目将是如何进行比较。
在trackedValue
是null
的情况下,考虑您的行bool check3 = trackedValue >= DateTime.Now
。对于Nullable<DateTime>
,它有点像这样(请注意,这并不是确切的,请参阅Eric的系列。这只是为了传达概念(:
check3 = trackedValue.HasValue ? trackedValue.Value >= DateTime.Now : false;
编译器甚至避免调用转换运算符。另一方面,您的会尝试运行隐式转换(假设您将其切换为隐式(,这可能会导致不受欢迎的NullReferenceException
(隐式运算符应该而不是抛出异常(。Nullable<T>
将转换运算符定义为explicit
的原因是,对于那些直接强制转换的情况(例如,DateTime casted = (DateTime)myNullableDateTime;
(,如果值为null,则可能引发异常。
您显式地声明了转换运算符,因此当bool check3 = trackedValue >= DateTime.Now; //Does not work
时,这应该起作用:
bool check3 = (DateTime)trackedValue >= DateTime.Now;
当然,另一种做法是宣布它是隐含的。
将运算符T
更改为隐式:
public static implicit operator T(TrackedValue<T> value)
{
return value.Value;
}