【问题标题】:using get vs property vs method [duplicate]使用get vs property vs方法[重复]
【发布时间】:2009-03-23 23:26:12
【问题描述】:

如果我在一个类中有一个私有属性,我想知道以下三种场景(内存使用、可用性、最佳实践等)在技术上的区别是什么:

class testClass
{
     private string myString1 = "hello";

     private string myString2 { get { return "hello"; } }

     private string myString3() { return "hello"; }
}

除了显然能够在 myString1 中设置值而不是在 myString2 或 myString3 中设置值之外,我想更多地了解它们在效率方面有何不同?

【问题讨论】:

  • 这个问题已经回答了无数次了。
  • 我确定它有,但请相信我,我在发布之前用谷歌搜索并搜索了这个网站大约 10 分钟。

标签: c#


【解决方案1】:

我尽量遵守这些规则:

  • 字段应保密
  • 应该使用属性来公开数据
  • 应该使用方法来执行操作

在某些情况下,每一次性能下降都很重要,但总的来说,我会尝试遵循最佳实践,直到分析告诉您需要优化。

这里有一篇好文章:Why Properties Matter

【讨论】:

    【解决方案2】:

    我个人更喜欢没有副作用的属性和显式 getter,如果某些东西是动态计算的。例如:

    class User {
        private string username;
    
        public string Username {
            get { return username; }
            set { username = value; }
        }
    
        public Post GetLatestPost() {
            // query the database or whatever you do here.
        }
    }
    

    而且我见过的很多 API 似乎都在做类似的事情。希望对您有所帮助。

    【讨论】:

      【解决方案3】:

      所有这些方法在编译成什么方面都非常不同,尽管在使用方面非常相似。我将尝试简要总结差异:

      1. 这是一个简单的私有实例变量。引用时它很容易成为最有效的。

      2. 这是一个只读属性(即一个 get 但没有 set 访问器)。

      3. 这是一个普通的无参数函数。我怀疑您只是提供这些示例纯粹是为了进行比较,并意识到这样的功能完全没用(在几乎所有情况下,私有属性也是如此)。布局(即一行中的所有内容)也相当糟糕。

      方法 2 和 3 与方法 1 相比效率同样低,因为它们都涉及函数调用的开销。我不知道它们都编译成的 CIL 代码(也许其他人可以生成),但它们肯定涉及更多指令,而引用 myString1 应该只需要 CIL 中的一条指令。

      不确定我是否可以在不了解更多上下文的情况下对最佳实践做出非常有用的评论,但方法 2(即私有财产)通常被认为毫无用处。我认为永远不应该使用第三种方法(它乞求变成财产)。我认为您真正想要的只是一个普通的旧私有变量,所以一定要进行第一个声明。公共值应始终作为属性而不是类中的变量进行访问(即属性的私有/受保护的支持变量),但这与您的问题有点无关。 (无论如何,您可以在快速搜索中找到大量讨论此问题的资源。)最后,请注意,如果您的“属性”将是只读的(即在任何时候都不会修改),那么您真的想使用一个常量,即private const string myString1 = "hello";

      希望这有助于澄清一些事情。

      【讨论】:

      • 得知 C# 编译器无法检测到这样的基本优化,我会感到震惊。他们肯定都编译成同一个东西吗?
      • C# 编译器不会优化它,但 JIT 编译器会。 x86 JIT 的能力和 x64 JIT 的能力是有区别的,主要是 x86 JIT 在这方面要好得多。 x64 JIT 不会为 exaple 的属性优化方法调用。
      • 即使 JIT 最终优化了 2. 和 3.,为了良好的实践和可读性,最好不要依赖它。
      【解决方案4】:

      这是个好问题:

      您有以下选择:

      private string myString = "hi!";   //Private Field
      
      public string MyString             //Property created to the private field
      {
        get {return myString;}
      }
      
      public string myString {get; private set;}   //VS2008 automatic properties
      
      public string getMyString()                  //Method Way
      {
         return myString;
      }
      

      如您所见,想法是一样的,不违反封装原则。用你觉得更舒服的,都可以达到目的,但我推荐属性方式或者 VIsual Studio 2008 自动属性。

      比方法更简洁明了。

      希望这会有所帮助!

      问候!!

      【讨论】:

        【解决方案5】:

        就最佳实践而言,

        class testClass
        {
           private string _myString;
        
           public string myString { get { return _myString; } set { _myString = value; } }
        
           public testClass()
           {
              myString = "Hello";  // Initial value.
           }
        }
        

        一般推荐,因为它实现了封装(隐藏内部状态,以便所有操作都通过方法/接口)。当然,setter 和 getter 通常是方法本身。

        在 C# 3.0 中,您可以将上面的内容替换为:

        class testClass 
        {    
          public string myString { get; set; }
        
          public testClass()
          {
              ...
          }
        }
        

        就效率而言,您真的应该考虑直接访问变量是否比属性更有效。差异是如此之小(如果有的话),最佳实践指南如此清晰,以至于您担心效率会误入歧途。

        【讨论】:

          【解决方案6】:

          以上所有关于设计、风格等的讨论都是有效的。但问题是关于性能。很容易测试。在每个调用周围包裹一些计时器,重复到 int32.Max。 在我的机器上,下面的代码显示 myString1 快得多。 (请注意,我必须更改类定义以公开成员):

              private void button2_Click(object sender, EventArgs e)
              {
                  //performance test
                  testClass t = new testClass();
                  System.Diagnostics.Stopwatch sw1 = new System.Diagnostics.Stopwatch();
                  sw1.Start();
                  for (int i = 0; i < int.MaxValue; i++)
                  {
                      string result = t.myString1;
                  }
                  sw1.Stop();
          
                  System.Diagnostics.Stopwatch sw2 = new System.Diagnostics.Stopwatch();
                  sw2.Start();
                  for (int i = 0; i < int.MaxValue; i++)
                  {
                      string result = t.myString2;
                  }
                  sw2.Stop();
          
                  System.Diagnostics.Stopwatch sw3 = new System.Diagnostics.Stopwatch();
                  sw3.Start();
                  for (int i = 0; i < int.MaxValue; i++)
                  {
                      string result = t.myString3();
                  }
                  sw3.Stop();
                  MessageBox.Show(string.Format("Direct: {0}, Getter: {1}, Method: {2}"
                      , sw1.ElapsedMilliseconds.ToString()
                      , sw2.ElapsedMilliseconds.ToString()
                      , sw3.ElapsedMilliseconds.ToString()));
              }
          
          
          class testClass 
          { 
              public string myString1 = "hello";
              public string myString2 { get { return "hello"; } }
              public string myString3() { return "hello"; } 
          }
          

          【讨论】:

          • 因为“易于测试”,我认为你搞砸了。第一个循环可能已经被编译器完全优化了,因为它什么都不做,但是第二个和第三个循环是函数调用,不能那么容易地优化出来。尝试在循环中添加更多处理并再次检查。
          • 你可能是对的,但我添加了一个整数,正在添加字符串的长度,结果仍然非常糟糕 - 该字段仍然更快。
          • 那你要分享速度结果吗?
          • 运行代码:),自己看看。我的结果是:Direct:4967,Getter:7350,Method:7164。您的里程可能会有所不同,但我想比率会相似 - 即直接访问要快得多。
          猜你喜欢
          • 2012-09-17
          • 1970-01-01
          • 1970-01-01
          • 2017-08-11
          • 2012-08-10
          • 1970-01-01
          • 2014-05-20
          • 2011-04-19
          相关资源
          最近更新 更多