我正在尝试构建一个行为类似于Nullable<T>
的类,特别是我可以访问Nullable<T>
类的基础值而无需显式调用nullable.Value
的方式。
在以下示例中,check1
&amp; check2
都有效。
Nullable<DateTime> nullable = new DateTime();
bool check1 = nullable >= DateTime.Now; //Works
bool check2 = nullable.Value >= DateTime.Now; //Works
我构建了自己的类TrackedValue
,它会记住它包装的值是否已更改。我的基础是Nullable<T>
并构建了隐含的&amp;显式运算符。
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
任何指针都会受到赞赏。
答案 0 :(得分:2)
该行明确无效,因为它需要进行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有一个excellent blog series。
据我所知,编译器本身将写入的代码/ IL改为完全不同的指令集。 Eric的third entry系列剧开始证明这一点。这是因为它通常我认为它处理空值的特殊情况。
我不确定你是否可以解决这个问题,但也许最简单的方法是简单地将一个转换运算符标记为implicit
,并希望它不会对你造成任何重大问题TrackedValue<T>
和Nullable<T>
之间的一致性。
编辑:其中一个不一致的项目将说明如何进行比较。
在bool check3 = trackedValue >= DateTime.Now
为trackedValue
的情况下,请考虑您的第null
行。对于Nullable<DateTime>
,它有点像这样(请注意,这不是完全它是什么,请参阅Eric的系列。这仅用于传达概念):
check3 = trackedValue.HasValue ? trackedValue.Value >= DateTime.Now : false;
编译器避免甚至调用转换运算符。另一方面,你的会尝试运行隐式转换(假设你将其转换为隐式转换),这可能会导致NullReferenceException
不受欢迎(隐式运算符应该不抛出异常)。 Nullable<T>
将转换运算符定义为explicit
的原因是因为对于那些直接转换的时间(例如DateTime casted = (DateTime)myNullableDateTime;
),如果值为null,则会抛出异常。
答案 1 :(得分:1)
您已明确声明转换运算符,因此在bool check3 = trackedValue >= DateTime.Now; //Does not work
时,这应该有效:
bool check3 = (DateTime)trackedValue >= DateTime.Now;
另一种行动方式当然是宣称它是隐含的。
答案 2 :(得分:1)
将运算符T
更改为隐式:
public static implicit operator T(TrackedValue<T> value)
{
return value.Value;
}