在getter中创建对象是不是很糟糕?

时间:2010-01-20 13:34:11

标签: c# oop getter

让我们在这样的getter中创建一个对象:

public class Class1
{
       public string Id { get; set; }
       public string Oz { get; set; }
       public string Poznamka { get; set; }

       public Object object
       {
             get
             {
                  // maybe some more code
                  return new Object { Id = Id, poznamla = Poznamka, Oz = OZ };
             }
        }
 }

或者我应该创建一个将创建并返回对象的方法?

14 个答案:

答案 0 :(得分:22)

是的,这是不好的做法。

理想情况下,getter不应该更改或创建任何内容(除了延迟加载,即便如此,我认为它会导致代码不太清晰......)。这样可以最大限度地降低无意识副作用的风险。

答案 1 :(得分:16)

属性看起来像字段,但它们是方法。众所周知,这会造成惊人的混乱。当程序员看到似乎正在访问字段的代码时,程序员做出的许多假设可能不适用于某个属性。所以有一些常见的属性设计指南。

  1. 避免从属性getter返回不同的值。如果连续多次调用,则属性方法每次都可以返回不同的值;每次返回相同的值。

  2. 属性方法可能需要额外的内存或返回对实际上不属于对象状态的内容的引用,因此修改返回的对象对原始对象没有影响;查询字段始终返回对保证属于原始对象状态的对象的引用。使用返回副本的属性可能会让开发人员感到非常困惑,而且这种特性通常没有记录。

  3. 考虑不能将属性作为out或ref参数传递给方法;一个字段可以。

  4. 避免长时间运行属性getter。属性方法可能需要很长时间才能执行;现场访问总是立即完成。

  5. 避免从getter中抛出异常。

  6. 如果属性设置器抛出异常,请保留以前的值

  7. 避免可观察到的副作用。

  8. 允许以任何顺序设置属性,即使这会导致对象暂时无效状态。

  9. <强>来源

    CLR via C#”,杰弗里里希特。第9章智能定义属性

    Framework Design Guidelines”第2版,Brad Abrams,Krzysztof Cwalina,第5.2章物业设计

答案 2 :(得分:8)

如果你希望你的getter在每次访问时都创建一个新对象,那就是这样做的方法。此模式通常称为Factory Method

然而,这通常不需要在属性(即getter和setter)上,因此被认为是不好的做法。

答案 3 :(得分:4)

是的,它是......从外面看,它应该是透明的,无论你是访问一个属性还是一个字段......

当从字段或属性中读取两次时,您需要两件事:

  • 对象的(外部)行为没有影响
  • 你得到相同的结果

我对C#并不了解,但我希望,以下内容清楚地说明了这一点。让我们这样开始:

Object o1 = myInst.object;
Object o2 = myInst.object;
o1.poznamka = "some note";

如果是字段,则以下条件为真:

o1 == o2;
o2.poznamka == "some note";

如果你使用带有getter的属性,每次调用都会返回一个新对象,这两个条件都将为false ...

你的getter似乎是为了生成你的实例的临时快照...如果这是你想要做的,而不是使它成为一个简单的方法......它避免了任何含糊不清......

答案 4 :(得分:2)

对于所有意图和目的,财产应该像一个领域。这意味着不应抛出任何异常,并且不应创建新对象(因此,如果在循环中使用该属性,则不会创建大量不必要的对象)

请改用包装类或类似方法。

答案 5 :(得分:2)

根据我的说法,如果某些东西是'属性',那么getter应该返回一个与该对象相关的属性(基本上是已经存在的数据)。

在您的情况下,您返回的内容当时不属于该对象的属性。您没有返回对象的属性,而是返回某个操作的产物。

我会使用类似GetMyObject()的方法。特别是如果有'行动'将会发生,我认为大多数时候最好有一个方法而不是属性 name

并试着想象一下,在看到您的房产后,其他不熟悉您的代码的开发人员会发现什么。

答案 6 :(得分:1)

属性只是表达计算字段的便捷方式。

它仍应代表关于对象的内容,无论值本身是如何到达的。例如,如果相关对象是发票,则可能需要累计每个订单项的费用,并返回总计。

问题中写的内容违反了该规则,因为返回对象的副本并不是描述对象的内容。如果返回值在对属性的调用之间发生更改而没有显式更改对象状态,则对象模型将被破坏。

总的来说,返回一个像这样的新对象几乎总会破坏规则(我现在想不出反例),所以我会说这是不好的做法。

还有一些属性,您可以轻松无辜地多次调用属性并最终运行相同的代码(希望不会很慢!)。

答案 7 :(得分:1)

为了编写易于测试的代码,您必须保持对象初始化的分离。

即在测试用例中,您没有持有测试某些特定项目。

像在House对象中一样,你不想测试与厨房对象有关的任何东西。 而你只测试花园。所以当你在一些构造函数或者getter中启动一个house类并启动对象时,你将不会编写好的代码来支持测试。

答案 8 :(得分:1)

除了已经发表的评论之外,当通过属性延迟加载字段时,您可能会遇到一些真正的调试问题。

我有一节课

private Collection<int> moo;

public Collection<int> Moo
{
  get 
  {
    if (this.moo == null) this.moo = new Collection<int>();
    return this.moo;
  }
}

然后在课堂的其他地方有一个引用

的公共方法
this.moo.Add(baa);

没有检查它是否被实例化。

它按预期抛出了一个空引用异常。但是这个例外是在一个UI线程上,因此并不是很明显它来自哪里。我开始追踪,每次我追查时,错误消失了。

有一段时间我不得不承认我以为自己疯了。调试器 - 没有错误。运行时,错误。稍后我发现了很多问题,我发现错误,并意识到 Visual Studio调试器正在实例化集合,因为它显示了类的公共属性。

答案 9 :(得分:0)

struct可能最多可以接受。对于引用类型,我只会在使用一些延迟加载模式进行一次时在getter中创建一个新对象。

答案 10 :(得分:0)

这取决于吸气剂的使用。这是一个包含这种延迟加载代码的好地方。

答案 11 :(得分:0)

这是一种不好的做法。在您的示例中,每次访问Object属性时,您应该能够期望相同的object

答案 12 :(得分:0)

正如你所说的那样它很糟糕,但并没有类似于可接受的延迟加载练习,可以在这里阅读。

http://www.aspcode.net/Lazy-loading-of-structures-in-C-howto-part-8.aspx

答案 13 :(得分:0)

这是一种不好的做法。但是,如果你把对象想象成一堆吸气剂&amp;你应该检查有关该主题的经典讨论。

正如一些人提到的,延迟加载可能是这样做的原因。取决于您在此处建模的实际业务逻辑。如果出于易读性目的更好,则应创建一个单独的方法,但如果创建对象的代码很简单,则可以避免间接。