C# GetObject(i)比Object[i]有什么优势?

C# GetObject(i)比Object[i]有什么优势?,c#,.net,collections,properties,accessor,C#,.net,Collections,Properties,Accessor,我正在重构前一位开发人员的一些C#数据访问代码,我对他使用的模式很好奇 代码最初公开了各种ActiveRecord样式的业务对象的集合(数组)——本质上是包装数据库字段的对象。我正在将数组更改为泛型列表,但我对代码的一个方面感到好奇的是,以前的开发人员对于他包装的每种类型的对象都有Get方法,因此: public Thing GetThing(int i) { return things[i]; } 这些方法有好几种,我想不出使用这种机制比直接引用事物有什么好处。为了论证起见,让我们假

我正在重构前一位开发人员的一些C#数据访问代码,我对他使用的模式很好奇

代码最初公开了各种ActiveRecord样式的业务对象的集合(数组)——本质上是包装数据库字段的对象。我正在将数组更改为泛型列表,但我对代码的一个方面感到好奇的是,以前的开发人员对于他包装的每种类型的对象都有Get方法,因此:

public Thing GetThing(int i) {
    return things[i];
}
这些方法有好几种,我想不出使用这种机制比直接引用事物有什么好处。为了论证起见,让我们假设事物是一个公共属性,而不是一个公共字段(在本例中,它实际上是一个自动实现的属性,所以该假设实际上是正确的)

我错过了什么明显的东西吗?甚至是一些深奥的东西

更新 我可能应该澄清,这些集合当前是从for循环中访问的:

for (int i = 0; i < thingsCount; i== ) {
    dosomthing( GetThing(i) );
    dosomethingelse( GetThing(i) );
}
for(int i=0;i
我正在对其进行重构:

for (int i = 0; i < thingsCount; i== ) {
    Thing thing = things[i];
    dosomthing( thing );
    dosomethingelse( thing );
}
for(int i=0;i

甚至可以使用things.foreach()。

这里有两件事需要注意。首先,您希望保持对象变量私有,并使用getter和setter来访问它们。这可以防止用户意外更改或修改对象变量

其次,它被认为是一种良好的命名约定,在直接访问属性时必须使用术语get/set。这有助于提高可读性

虽然在本例中它是一个公共属性,但使用getter和setter可以提高可读性并帮助防止意外行为。无论您是否正在访问循环中的对象变量,都应该继续使用
getting
约定

最后,如果从对象内部访问变量,则不需要使用getter或setter

注意:通常认为保持对象变量私有并对所有语言使用getter/setter是一种很好的风格


您可能还对问题“

感兴趣,您可能希望将对象公开为
IList
。这将为您提供所需的索引功能,但您也可以使用LINQ函数的范围,例如根据条件创建新的项目列表。Plus
IList
实现了
IEnumerable
,因此您可以使用
foreach
来循环对象

e、 g.在你们班:

public IList<Thing> Things { get; private set; }


我不知道这是否显而易见,但我确实认为你遗漏了什么

假设
things
是一个
IList
。然后直接公开它(如
事物
)将允许调用代码调用
添加
插入
删除
,等等。也许以前的开发人员不想允许这样做(我相信有很多很好的理由)

即使假设它是一个
东西[]
(因此
添加
等将不可用),将其公开仍然允许调用代码执行类似于
obj.Things[0]=newthing()的操作
这可能是不允许的操作,具体取决于类的实现

您可以将
事物
公开为
只读集合
,它将解决大多数这些问题。但归根结底是这样的:如果开发人员只想允许调用代码通过索引访问项——仅此而已——那么提供一个
getting
方法作为实现这一点的手段,老实说,这是迄今为止最有意义的

现在,当然还有这个选项:只使用
get
访问器实现
this[int]
属性。但是,只有当所讨论的类本质上是一个独占的
对象的集合时,这才有意义(即,在类中不存在您想要提供访问权限的其他类型的对象的集合)

总而言之,我认为
GetThing
方法非常合理

也就是说,从你的措辞来看,前一位开发者确实做出了一些非常糟糕的决定:

  • 如果他/她也将
    物品
    收藏直接作为公共财产公开,那么。。。这违背了
    getting
    方法的全部目的,不是吗?结果只是一个臃肿的接口(我通常认为,当您有多个方法来完成完全相同的事情时,这不是一个好迹象,除非出于某种合理的原因,它们被清楚地记录为别名)。[更新:似乎以前的开发人员没有这样做。很好。]
  • 看起来以前的开发人员也在使用
    GetThing
    方法从
    things
    内部访问项目,这在我看来太傻了。为什么在类本身中使用类的公共接口引入额外方法调用的无意义开销?如果您在类中,那么您已经在实现中了,并且可以访问所有您想要的私有/受保护的数据——无需假装其他

  • 如果我不得不猜测的话,我会说这个开发人员已经习惯了其他一些语言,比如Java,并且没有完全了解C#的标准实践。“get[Property]”术语在Java、javascript等语言中大量使用。C#用属性和索引器代替了它。属性与getter和setter一样强大,但更易于编写和使用。你通常在C#中看到“获取[某物]”的唯一时间是:

    • 手术很可能很昂贵,你真的需要
      Thing x = business.Things[3];
      
      var x = business.Things.Where(t => t.Name == "cori");
      
      T this[int i] { get; }
      
      public class ThingHolderDataAccess
      {
          public ThingHolder GetThingHolderForSomeArgs(int arg1, int arg2)
          {
              var oneThings = GetOneThings(arg1);
              var otherThings = GetOtherThings(arg2);
              return new ThingHolder(oneThings, otherThings);
          }
          private IEnumerable<OneThing> GetOneThings(int arg)
          {
              //...
              return new List<OneThing>();
          }
          private IEnumerable<AnotherThing> GetOtherThings(int arg2)
          {
              //...
              return new List<AnotherThing>();
          }
      }
      
      public class ThingHolder
      {
          public IIndexedReadonlyCollection<OneThing> OneThings
          {
              get;
              private set;
          }
      
          public IIndexedReadonlyCollection<AnotherThing> OtherThings
          {
              get;
              private set;
          }
      
          public ThingHolder(IEnumerable<OneThing> oneThings,
                             IEnumerable<AnotherThing> otherThings)
          {
              OneThings = oneThings.ToIndexedReadOnlyCollection();
              OtherThings = otherThings.ToIndexedReadOnlyCollection();
          }
      }
      
      #region These classes can be written once, and used everywhere
      public class IndexedCollection<T> 
          : List<T>, IIndexedReadonlyCollection<T>
      {
          public IndexedCollection(IEnumerable<T> items)
              : base(items)
          {
          }
      }
      
      public static class EnumerableExtensions
      {
          public static IIndexedReadonlyCollection<T> ToIndexedReadOnlyCollection<T>(
              this IEnumerable<T> items)
          {
              return new IndexedCollection<T>(items);
          }
      }
      
      public interface IIndexedReadonlyCollection<out T> : IEnumerable<T>
      {
          T this[int i] { get; }
      }
      #endregion
      
      var things = _thingHolderDataAccess.GetThingHolderForSomeArgs(a, b);
      foreach (var oneThing in things.OneThings)
      {
          // do something
      }
      foreach (var anotherThing in things.OtherThings)
      {
          // do something else
      }
      
      var specialThing = things.OneThings[c];
      // do something to special thing