当前位置:  开发笔记 > 编程语言 > 正文

在值对象的不可变对象和结构之间进行选择

如何解决《在值对象的不可变对象和结构之间进行选择》经验,为你挑选了4个好方法。

如何在实现值对象(作为地址的规范示例)作为不可变对象或结构之间进行选择?

选择一个是否具有表现,语义或任何其他好处?



1> Dan Herbert..:

有几点需要考虑:

在堆栈上(通常)分配结构.它是一种值类型,因此如果数据太大,则跨方法传递数据可能会很昂贵.

在堆上分配一个类.它是一种引用类型,因此通过方法传递对象并不昂贵.

通常,我将结构用于不太大的不可变对象.我只在它们中存有有限数量的数据时才使用它们,或者我想要不变性.一个例子是DateTime结构.我喜欢认为如果我的对象不像a那样轻量级DateTime,那么它可能不值得用作结构体.此外,如果我的对象没有意义作为值类型传递(也像DateTime),那么它可能没有用作结构.不变性在这里是关键.另外,我想强调结构默认情况下不是不可变的.你必须通过设计使它们不变.

在我遇到的99%的情况中,一个类是正确的使用方法.我发现自己不经常需要不可变的课程.在大多数情况下,我认为类是可变的更自然.


@Amby阅读这篇文章.它应该有助于你理解.http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx结构不需要装箱以分配给堆.

2> Bryan Watts..:

我喜欢用思想实验:

当只调用一个空构造函数时,此对象是否有意义?

根据Richard E的要求编辑

一个很好的用法struct是包装基元并将它们范围限定为有效范围.

例如,概率的有效范围为0-1.使用小数来表示这种情况很容易出错,需要在每个使用点进行验证.

相反,您可以使用验证和其他有用的操作来包装基元.这通过了思想实验,因为大多数原语具有自然的0状态.

以下是struct表示概率的示例用法:

public struct Probability : IEquatable, IComparable
{
    public static bool operator ==(Probability x, Probability y)
    {
        return x.Equals(y);
    }

    public static bool operator !=(Probability x, Probability y)
    {
        return !(x == y);
    }

    public static bool operator >(Probability x, Probability y)
    {
        return x.CompareTo(y) > 0;
    }

    public static bool operator <(Probability x, Probability y)
    {
        return x.CompareTo(y) < 0;
    }

    public static Probability operator +(Probability x, Probability y)
    {
        return new Probability(x._value + y._value);
    }

    public static Probability operator -(Probability x, Probability y)
    {
        return new Probability(x._value - y._value);
    }

    private decimal _value;

    public Probability(decimal value) : this()
    {
        if(value < 0 || value > 1)
        {
            throw new ArgumentOutOfRangeException("value");
        }

        _value = value;
    }

    public override bool Equals(object obj)
    {
        return obj is Probability && Equals((Probability) obj);
    }

    public override int GetHashCode()
    {
        return _value.GetHashCode();
    }

    public override string ToString()
    {
        return (_value * 100).ToString() + "%";
    }

    public bool Equals(Probability other)
    {
        return other._value.Equals(_value);
    }

    public int CompareTo(Probability other)
    {
        return _value.CompareTo(other._value);
    }

    public decimal ToDouble()
    {
        return _value;
    }

    public decimal WeightOutcome(double outcome)
    {
        return _value * outcome;
    }
}



3> Konrad Rudol..:

如何在实现值对象(作为地址的规范示例)作为不可变对象或结构之间进行选择?

我认为你的选择是错误的.不可变对象和结构不是对立的,它们也不是唯一的选择.相反,你有四个选择:

易变的

一成不变

结构

易变的

一成不变

我认为在.NET中,默认选择应该是表示逻辑可变类和表示实体不可变类.实际上,即使对于逻辑实现,我也倾向于选择不可变类,如果可行的话.应该为模拟值语义的小类型保留结构,例如自定义类型,数字类型类似的实体.这里的重点是小的,因为你不想复制大量的数据,而通过引用的间接实际上很便宜(所以我们通过使用结构不会获得太多收益).我总是倾向于制作结构DateComplex不可变的(我现在想不出一个例外).由于这最适合内在价值类型的语义,我发现遵循一个很好的规则.


@AviD:这个讨论没有实际意义.你用符号混淆价值.这些在计算机科学中具有非常明确的含义,微软因为术语草率而感到羞耻.但事实是:变量是一个*符号*,除非你在.NET中声明`const`或`readonly`,否则变量总是可变的.另一方面,价值是完全不同的..NET中的值对于所有基本类型都是不可变的.你无法改变一个价值,故事结束.您所能做的就是为现有符号分配新值.(继续 …)

4> peterchen..:

因素:建筑,记忆要求,拳击.

通常,构造函数对结构的限制 - 没有明确的无参数构造函数,没有base构造 - 决定是否应该使用结构.例如,如果参数的构造函数应该没有初始化的成员为默认值,使用不可变对象.

如果您仍然可以在两者之间做出选择,请确定内存要求.小项应该存储在结构中,特别是如果你期望很多实例.

当实例被装箱时(例如,为匿名功能捕获或存储在非通用容器中),这种好处就会丢失 - 你甚至开始为拳击支付额外费用.


什么是"小",什么是"很多"?

在32位系统上,对象的开销是(IIRC)8字节.请注意,对于几百个实例,这可能已经决定内部循环是否在缓存中完全运行,或者调用GC.如果您期望成千上万的实例,这可能是运行与爬网之间的差异.

从那个POV,使用结构不是一个不成熟的优化.


所以,作为经验法则:

如果大多数实例都会被装箱,请使用不可变对象.
否则,对于小对象,仅当结构构造会导致界面笨拙并且您期望不超过数千个实例时才使用不可变对象.

推荐阅读
殉情放开那只小兔子
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有