【问题标题】:When to use private properties (with no special logic) [duplicate]何时使用私有属性(没有特殊逻辑)[重复]
【发布时间】:2020-02-28 09:18:35
【问题描述】:

最近我一直在阅读一些关于在 C# 中始终使用属性而不是公共字段的主题,但是私有属性呢?当然,也有一些关于它的线程,但他们几乎总是谈论额外的逻辑/延迟加载等。

假设我有一个只读字段,它将在 Program 类周围被访问,但是(至少现在)它没有在其他任何地方使用:

static class Program
{
    private static readonly Canvas canvas = new Canvas(100, 30);
    // Canvas is like the main class of my game, there can be only one instance of it

    static void Main()
    {
        // ...
        canvas.DoSomething();
        // ...
    }

    // ...
    // Many other references to "canvas" here
}

或者我应该这样做:

private static Canvas Canvas { get; } = new Canvas(100, 30);

第二个选项意味着我可以轻松地将其公开,我将来可能会也可能不会这样做。那么其他私有领域呢?关于什么应该是私有财产,是否有任何规则或指导方针?或者我应该将所有内容都声明为一个字段,因为它是私有的(尽管感觉是公共的)?

只是为了澄清:

  • 我不是在做一个可重用的库,只是一个主机游戏;
  • 我不会实现任何关于获取/设置值的逻辑;
  • 我正在自己编写 Canvas 类,它不是外部的。

【问题讨论】:

  • 这更像是一个软件工程问题,而不是 StackOverflow 的问题,请参阅 softwareengineering.stackexchange.com/questions/160876/…。话虽如此,正如 Eric Lippert here 所说,私有属性(使用 setter)的一个非常明显的优势是,当您想知道谁设置值以及何时设置值时,您可以更好地调试它们。

标签: c# properties private encapsulation


【解决方案1】:

属性是私有变量之上的包装器。

私有属性与私有变量一样好。没有区别。 如果您不打算在类外使用该变量,则只需使用该变量即可。

你也使用了只读。 readonly 的唯一目的是它只能在构造函数内部启动。

我希望这能回答你的问题。

【讨论】:

    【解决方案2】:

    使用私有属性是没有用的,因为只有当前的类成员可以访问它并且它是可读写的。

    除非你只想在构造函数或声明级别初始化它,并且不允许在其他方法中写入,否则你可以这样写:

    private MyField { get; }
    

    声明只读字段和此类属性之间的区别在于,属性读取访问器是一种方法,因此它会导致每次访问都消耗 CPU proc 调用滴答,这不需要只读属性。

    所以这是一个速度性能问题,否则它是相同的最终性。

    这是一个测试类:

    public class Test
    {
      private readonly int MyField = 10;
      private int MyProperty { get; }
      public Test()
      {
        MyProperty = 10;
      }
      public void Method()
      {
        var value1 = MyField;
        var value2 = MyProperty;
      }
    }
    

    这里是编译器生成的IL代码:

    // int myField = MyField;
    IL_0001: ldarg.0
    IL_0002: ldfld int32 ConsoleApp.Test::MyField
    IL_0007: stloc.0
    
    // int myProperty = MyProperty;
    IL_0008: ldarg.0
    IL_0009: call instance int32 ConsoleApp.Test::get_MyProperty()
    IL_000e: stloc.1
    

    对于只读字段,只有将值加载到堆栈中,CLR 将其替换为目标处理器加载到寄存器指令中,即快速 (MOV)。

    有一个属性有一个 .NET 方法调用,CLR 将其替换为目标处理器过程调用指令,这会占用大量 CPU 滴答以及返回 (CALL/RET)。

    .method private hidebysig specialname instance int32 get_MyProperty () cil managed 
    // return MyProperty;
    IL_0000: ldarg.0
    IL_0001: ldfld int32 ConsoleApp.Test::'<MyProperty>k__BackingField'
    IL_0006: ret
    

    所以一个属性比只读字段需要更多的 CPU 周期,但在操作方面结果是相同的(我会说一个错误的值,因为我不记得 x486 并且它很旧,但想象一下它可能产生想法的速度要慢约 5 到 20 倍)。

    因此,如果速度不重要,则优先考虑。您可以毫无问题地更改为 public,高级设计保持不变:速度和外观没有区别。

    也就是说,请记住,Visual Studio 设计器、组件设计和序列化等需要公共属性。因此,使用属性可能会节省时间并且更聪明。

    https://superuser.com/questions/643442/latency-of-cpu-instructions-on-x86-and-x64-processors

    【讨论】:

    • 好吧,我不太关心性能那么,我想了解更多关于代码清洁度和可读性的问题,但谢谢(给你点赞)
    • 谢谢,我只是在最后添加了一个注意事项,以便使用将来可能标记为公开的属性。
    • 是的,如果有人每分钟进行一百万次编辑,很难不注意到:D
    • 对不起,没有预览按钮,我喜欢从真实的角度和其他问题的角度来改进。
    猜你喜欢
    • 2020-05-25
    • 1970-01-01
    • 2013-12-27
    • 2012-12-26
    • 1970-01-01
    • 2021-05-20
    • 1970-01-01
    • 2020-11-15
    • 1970-01-01
    相关资源
    最近更新 更多