【问题标题】:How to use properties with an integral overflow (byte)?如何使用具有整数溢出(字节)的属性?
【发布时间】:2020-11-14 02:43:42
【问题描述】:

我对编程和 C# 还很陌生,我正在使用 C# 9.0 创建一个游戏,其中 Entity 的所有实例都有特定的统计数据。我希望能够使用属性更改他们的私有数据字段,尽管我不完全确定属性是如何工作的。我知道它们在封装中作为 getter 和 setter 很有用。

上下文

  • 我正在尝试优化代码并尽可能减少内存使用量
  • 字节字段str 应该是可变的(通过事件、培训等),但有“上限”和“下限”
    • 如果dog.str = 253,那么dog.Str += 5; 应该导致dog.str 为255
    • 如果dog.str = 2,那么dog.Str -= 5; 应该导致dog.str 为0
private byte str;
public short Str
{
    get => str;
    set
    {
        if (value > byte.MaxValue) str = byte.MaxValue;       //Pos Overflow
        else if (value < byte.MinValue) str = byte.MinValue;  //Neg Overflow
        else str = (byte)value;
    }
}

问题

  • 由于该属性的数据类型为 Short,它是否会创建一个新的消耗内存的私有支持字段?还是value/Str{set;} 只是一个后来消失的局部变量?

    • 属性public float StrMod {get =&gt; (float)(str*Effects.Power);} 是否创建支持字段?只创建一个类似public float getStrMod() 的方法会更好吗?
  • 这段代码是否最适合我想要实现的目标?考虑到以下几点,有没有更好的方法来做到这一点?

    • 如果由于某种原因 Short 溢出(在这种情况下不太可能,但可能存在类似情况),那么我最终会遇到同样的问题。但是,如果额外的内存分配不是问题,那么我可以使用 int。
    • {get;} 将返回一个 Short,这可能是也可能不是问题。

【问题讨论】:

    标签: c# memory properties byte integer-overflow


    【解决方案1】:

    问题 1:

    不,它没有,它的支持字段是str

    问题 2:

    首先分析您的代码,而不是进行随机更改以希望减少内存使用量。

    “过早的优化是万恶之源”,你现在真的有这样的问题吗?

    为了简单起见,我个人会使用 int 并为属性和支持字段使用相同的类型。

    这将避免包装,例如分配32768,这将导致-32768 for short

    旁注,不要认为使用byte 一定会导致1 个字节,如果您有严格的打包要求,那么您需要查看StructLayoutAttribute.Pack

    除此之外,我认为您的代码没有任何问题,只需首先让它工作,然后对其进行优化!


    我会这样写你的代码,也许你会从中得到一些想法:

    class Testing
    {
        private int _value;
    
        public int Value
        {
            get => _value;
            set => _value = Clamp(value, byte.MinValue, byte.MaxValue);
        }
    
        private static int Clamp(int value, int min, int max)
        {
            return Math.Max(min, Math.Min(max, value));
        }
    }
    

    编辑:

    不同的场景:

    class Testing
    {
        private int _value1;
    
        public int Value1 // backing field is _value1
        {
            get => _value1;
            set => _value1 = value;
        }
    
        public int Value2 { get; set; } // adds a backing field
    
        public int Value3 { get; } // adds a backing field
    
        public int Value4 => 42; // no backing field
    }
    

    正如您可能已经猜到的那样,属性是 syntactic sugar 的方法,与只能分配值的字段相比,它们可以在后台做“任何事情”。

    另外,方法的一个区别是你可以在调试器中浏览它的值,这很方便。

    推荐阅读:

    https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties

    最后,预计属性会快速返回,否则编写一个方法,如果需要一段时间,可能还需要async(在这种情况下,方法的优势在于属性不能是async)。

    【讨论】:

    • 好的,酷!并感谢您的建议。我只是认为它已经是这样,将来很难改变。我在想你的 Clamp() 方法,但忘记了如何抽象地实现它(因为我以前做过类似的事情)。最大值和最小值是任意的,因为它只是数据类型的限制(现在我可以让它变得正确)。
    • 我为缺乏礼节道歉,但如果您寻找“StrMod”,我在您回答之前编辑了我的第一个问题。如果有人也可以回答这个问题,我可以关闭这个问题(在这种情况下,我应该再发一个帖子吗?)。
    【解决方案2】:

    @aybe 回答涵盖了关于您问题的主要内容。我想为您的第二个问题添加其他信息。您应该考虑在哪个平台上编写应用程序。有一个word term

    在计算中,单词是特定数据使用的自然数据单位 处理器设计。一个词是一段固定大小的数据,被处理为 由指令集或处理器的硬件组成。这 字中的位数(字长、字宽或字长) 是任何特定处理器设计的重要特征或 计算机体系结构。

    如果处理器有 64 位字,那么每个类型小于 64 位的变量仍将占用 64 位内存。请记住,给定类型的变量将作为给定类型处理,并且内存中的大小不会影响范围、上溢或下溢 - 将为给定类型处理算术。

    简而言之 - 如果您有 64 位桌面处理器并且您将只使用 short 变量,那么与声明 int 变量相比,您不会观察到任何内存节省。

    【讨论】:

      猜你喜欢
      • 2022-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-28
      • 1970-01-01
      • 2014-11-05
      • 1970-01-01
      • 2019-04-07
      相关资源
      最近更新 更多