C# 声明/传递结构与声明/传递单个值

C# 声明/传递结构与声明/传递单个值,c#,.net,constructor,struct,performance,C#,.net,Constructor,Struct,Performance,实际上,我有两个问题。但它们之间的关系非常密切 假设我有这样一个简单的结构: public struct TradePrice { public float Price; public int Quantity; public TradePrice(float price, int quantity) { Price = price; Quantity = quantity; } } 问题1 现在,如果我有需要访问这些值的代码,

实际上,我有两个问题。但它们之间的关系非常密切

假设我有这样一个简单的结构:

public struct TradePrice {
    public float Price;
    public int Quantity;

    public TradePrice(float price, int quantity) {
        Price = price;
        Quantity = quantity;
    }
}
问题1 现在,如果我有需要访问这些值的代码,那么这样做有什么区别吗:

TradePrice tp = new TradePrice(50.0f, 100);
这是:

float p = 50.0f;
int q = 100;
我觉得第一个,因为它调用的是构造函数,应该有类似于方法调用的开销。但这只是一个猜测

问题2 上述问题的答案实际上可能也回答了这个问题,但也许有一些微妙之处使这些场景有所不同;所以我还是要问。假设我有一个结构,它本身有属于结构类型的成员。像这样:

public struct BidAsk {
    public TradePrice Bid;
    public TradePrice Ask;
}
那么这三种方法有什么区别吗

Reset(TradePrice bid, TradePrice ask) {
    Bid = bid;
    Ask = ask;
}

Reset(float bidPrice, int bidQuantity, float askPrice, int askQuantity) {
    Bid = new TradePrice(bidPrice, bidQuantity);
    Ask = new TradePrice(askPrice, askQuantity);
}

Reset(float bidPrice, int bidQuantity, float askPrice, int askQuantity) {
    Bid.Price = bidPrice;
    Bid.Quantity = bidQuantity;
    Ask.Price = askPrice;
    Ask.Quantity = askQuantity;
}
我倾向于认为结构的构造函数会有一些开销,因此即使在上述方法中传递/设置的数据量相同,第一个和最后一个方法可能会稍微更有效。这是真的吗?第一种方法和最后一种方法是否有所不同


为了记录在案,我不是在问这个问题,因为我错误地认为这会导致性能瓶颈,或者从设计的角度来看,它特别重要,尽管也许有人会认为这会让我大吃一惊。我这么问是因为我很好奇。

传递结构而不是单个值可能会带来更好的可维护性,因为如果需要更改结构定义,代码更改的影响会更低。

首先要解决更大的问题。这代码很难闻

问题1:使用二进制浮点数表示金融数量。二进制浮点数被设计用来表示科学量,其中最后几位精度的微小误差并不重要。它们极不适合表示精确的财务数量。如果要表示金融量,请始终使用十进制,切勿使用浮点

问题2:假设您有充分的理由使用二进制浮点,请不要使用浮点。使用双重密码。现代硬件优化为双精度算法,而不是单精度;在某些情况下,单个精度实际上较慢。当然,double占用的内存是float的两倍,但除非您同时在内存中存储了几百万个,否则这真的不重要。此外,您应该使用十进制,它比float大四倍

问题3:您有一个可变值类型。可变值类型是纯粹的邪恶。很容易意外地导致具有可变值类型的bug。避免

问题4:这真的是结构的正确名称吗?我认为交易价格将由价格属性表示。有没有更好的名称来描述它所代表的东西?它是否代表了您业务领域中的一些清晰概念

问题5:对传递给公共结构的公共构造函数的参数不进行验证。这似乎很危险。如果有人试图以-100000.00股的价格交易-100股,该怎么办。会发生什么?没什么好的,我敢打赌

问题6:结构的默认值应始终是该结构的有效实例。它是?此结构的默认实例是Price=0,Quantity=0。这真的有意义吗?如果没有,则不要将其设为结构。让它成为一门课

问题7:首先,这在逻辑上是一种值类型吗?为什么它是一个结构?这是您认为应该在逻辑上被视为一个值(如数字12)还是在逻辑上可以在多个位置(如客户)引用同一事物?如果逻辑上不是值,则不要使用值类型

假设名称正确,并且这在逻辑上是一种值类型,那么您的代码应该如下所示:

public struct TradePrice 
{ 
    public decimal Price {get; private set;}
    public int Quantity {get; private set; }
    public TradePrice(decimal price, int quantity) : this()
    { 
        if (price < 0m) throw new ...
        if (quantity < 0) throw new ...
        this.Price = price; 
        this.Quantity = quantity; 
    } 
} 

至于你的实际问题:没有逻辑上的区别。可能存在性能差异。我一点也不知道这里是否存在可测量的性能差异。您已经双向编写了代码。拿一块秒表,用两种方法运行十亿次,然后你就会知道问题的答案。

一个包含三个字段的结构的行为就像一组三个变量用胶带粘在一起。分配结构类型的字段或变量为这三个单独的字段分配空间,并且按值传递结构类型的值与分别传递三个字段的运行时成本基本相同

结构与一组单独变量之间的主要区别在于:1结构类型的单个数组包含每个元素中结构的所有字段。因此,如果MyPoint3d是一个结构,一个由50个元素组成的数组将保存x、y和z的所有50个值。如果单独使用字段 对于不同的坐标,必须创建三个不同的数组;2作为ref参数传递任何大小的结构只需要传递一个引用。接受结构类型(例如MyPoint3d)的ref参数的代码将知道通过该引用访问的x、y和z成员都属于同一个结构实例。相反,如果代码接受x坐标的ref参数、y坐标的ref参数和z坐标的ref参数,则无法知道它们是否是单个点的x、y和z坐标


顺便说一句,结构有公开的公共字段是好的,如果一个结构应该表示一个变量集合,没有更好的方法来说明这一点,但是结构方法修改它是不好的。最好使用接受结构类型的ref参数的静态方法。如果试图将只读结构作为声明的ref参数传递,编译器将发出嘎嘎声;相反,如果试图将只读结构传递给修改此结构的方法,则它们不会发出嘎嘎声。生成的代码不会工作,但不会生成任何编译器诊断。使用显式ref参数将确保无法运行的代码不会编译。

我现在没有时间写完整的答案,但请不要使用公共字段,也不要创建可变值类型。他们是邪恶的。最好的办法是做一个测试台,看看结果,我猜两者之间没有明显的区别。@Jon:我完全理解这两点,相信我。我所能说的就是,我有我的理由,而不是写一篇长篇大论的回复。他们是否有充分的理由是另一个讨论的话题。@Jeff:当然没有明显的区别。我几乎可以保证,即使不运行基准测试,也几乎可以,尽管人们永远不能假设这些事情!。真的,我只是想知道是否有任何区别。@Dan:你能解释一下,在你的头脑中,没有显著区别和根本没有区别的区别是什么吗?我不明白你在这里的逻辑意思。你好像在问,有什么区别,但实际上没有区别吗?对我来说,这不是一个明智的问题,因为它不接受任何可以想象得到答案的测试。