我正在尝试建立一个行为类似于Nullable<T>的类,特别是无需显式调用Nullable<T>即可访问nullable.Value类的基础值的方式。

在以下示例中,行check1check2均起作用。

Nullable<DateTime> nullable = new DateTime();
bool check1 = nullable >= DateTime.Now; //Works
bool check2 = nullable.Value >= DateTime.Now; //Works


我建立了自己的类TrackedValue,该类可以记住包装的值是否已更改。我基于Nullable<T>建立了隐式和显式运算符。

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的excellent blog series

据我了解,编译器本身将编写的代码/ IL完全更改为不同的指令集。埃里克(Eric)在该系列上的third entry开始证明这一点。这是因为我相信一般情况下它会处理null的特殊情况。

我不确定您是否可以解决此问题,但是最简单的方法可能只是将那里的一个转换运算符标记为implicit,并希望它不会对您造成任何有关和TrackedValue<T>

编辑:那些不一致的项目之一将是说如何进行比较。

如果Nullable<T>bool check3 = trackedValue >= DateTime.Now,请考虑您的行trackedValue。对于null来说,它就像这样(请注意,这并不完全相同,请参阅Eric的系列文章。这只是为了传达概念):

check3 = trackedValue.HasValue ? trackedValue.Value >= DateTime.Now : false;


编译器甚至避免调用转换运算符。另一方面,您的尝试运行隐式转换(假设您将其切换为隐式),这可能导致Nullable<DateTime>被皱眉(隐式运算符不应抛出异常)。 NullReferenceException将转换运算符定义为Nullable<T>的原因是,对于那些您直接进行转换的时间(例如explicit),如果该值为null,则可能引发异常。

关于c# - 建立行为类似于Nullable <T>的类,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16608685/

10-13 05:57