与objects[i]相比,objects.GetObject(i) 有什么优势吗?

发布于 2024-09-08 01:05:35 字数 813 浏览 4 评论 0原文

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

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

public Thing GetThing(int i) {
    return things[i];
}

这些方法有几种,我不能在我的一生中,我会考虑使用该机制相对于直接直接引用 things[i] 的任何可能的优势。为了便于论证,我们假设事物是公共财产,而不是公共字段(在这种情况下,它实际上是自动实现的财产,因此该假设实际上是正确的)。

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

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

for (int i = 0; i < thingsCount; i== ) {
    dosomthing( GetThing(i) );
    dosomethingelse( GetThing(i) );
}

我正在重构:

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

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

I'm refactoring a little bit of C# data access code from a previous developer and am curious about a pattern he used.

The code initially exposed collections (arrays) of a variety of ActiveRecord-style business objects - essentially objects wrapping database fields. I'm changing the arrays to generic lists, but the aspect of the code I'm curious about is that the previous developer had Get methods for each type of object he was wrapping, thusly:

public Thing GetThing(int i) {
    return things[i];
}

There are several of these methods, and I cannot for the life of me think of any possible advantage of using that mechanism over simply referring to things[i] directly. Let's assume, for argument's sake, that things is a public property, not a public field (in this case it's actually an auto-implemented property, so that assumption is actually true).

Am I missing something obvious? Or even something esoteric?

UPDATE
I should probably clarify that these collections are currently accessed from within for loops:

for (int i = 0; i < thingsCount; i== ) {
    dosomthing( GetThing(i) );
    dosomethingelse( GetThing(i) );
}

which I am refactoring to:

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

and perhaps even to use things.foreach().

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

难如初 2024-09-15 01:05:36

我不知道这是否很明显,但我确实认为你错过了一些东西。

假设 things 是一个 IList。然后直接公开它(作为 Things)将允许调用代码调用 AddInsertRemoveAt 等。也许以前的开发人员不想允许这样做(我确信有很多充分的理由)。

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

可以Things公开为ReadOnlyCollection,这可以解决大部分问题。但归根结底是这样的:如果开发人员想要允许调用代码通过索引访问项目(仅此而已),那么提供一个 GetThing 方法作为老实说,这样做的方法是迄今为止最有意义的。

现在,当然,还有这个选项:仅使用 get 访问器实现 this[int] 属性。但只有当相关类本质上是 Thing 对象的专门集合时,这才有意义(即,不存在一些其他的集合) em> 您想要在类中提供访问的对象类型)。

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

也就是说,从您提出问题的方式来看,听起来确实是之前的开发人员做出了一些其他相当糟糕的决定:

  1. 如果他/她公开了things集合直接作为公共财产,那么...这违背了 GetThing 方法的全部目的,不是吗?结果只是一个臃肿的界面(我通常认为,当您有多种方法来完成完全相同的事情时,这不是一个好兆头,除非出于某种合理的原因将它们明确记录为别名)。 [更新:看来之前的开发者没有这样做。很好。]
  2. 看起来以前的开发人员也在内部使用 GetThing 方法从 things 访问项目,这很愚蠢(在我看来)。为什么要从类本身内部使用类的公共接口引入额外方法调用的无意义开销?如果您在课堂上,那么您已经处于实现内部并且可以访问您想要的所有私有/受保护数据 - 无需假装。

I don't know if it's obvious, but I do think you're missing something.

Let's say things is an IList<Thing>. Then exposing it directly (as Things) would allow calling code to call Add, Insert, RemoveAt, etc. Maybe the previous developer didn't want to allow this (and I'm sure there are plenty of good reasons for that).

Even supposing it's a Thing[] (so Add, etc. wouldn't be available), exposing it as such would still allow calling code to do something like obj.Things[0] = new Thing(); which may be an operation that should not be allowed depending on the class's implementation.

You could expose Things as a ReadOnlyCollection<Thing> which would take care of most of these problems. But what it comes down to is this: if the developer only wants to allow calling code to access items by index -- nothing more -- then providing a single GetThing method as the means to do so, honestly, makes by far the most sense.

Now, granted, there's also this option: implementing a this[int] property with only a get accessor. But that only makes sense if the class in question is essentially a collection of Thing objects exclusively (i.e., there isn't also a collection of some other type of object you want to provide access to within the class).

All told, I think the GetThing approach is pretty sound.

That said, from the way you've worded your question, it does sound like the previous developer made some other pretty poor decisions:

  1. If he/she also exposed the things collection directly as a public property, well, then... that defeats the whole purpose of the GetThing method, doesn't it? The result is simply a bloated interface (I generally think it's not a great sign when you've got multiple methods to accomplish exactly the same thing, unless they're clearly documented as aliases for some justifiable reason). [Update: It appears the previous developer did not do this. Good.]
  2. It looks like the previous developer was also internally accessing items from things using the GetThing method, which is just silly (in my opinion). Why introduce the pointless overhead of extra method calls using a class's public interface from within the class itself? If you're in the class, you're already inside the implementation and can access private/protected data all you want -- no need to pretend otherwise.
烟花肆意 2024-09-15 01:05:36

您可能希望将该对象公开为 IList。这将为您提供所需的索引功能,但您还可以使用一系列 LINQ 函数,例如根据条件创建新的项目列表。另外,IList 实现 IEnumerable,因此您将能够使用 foreach 循环访问对象。

例如在你的课堂上:

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

例如用法:

Thing x = business.Things[3];

var x = business.Things.Where(t => t.Name == "cori");

You probably want to expose the object as an IList<Thing>. This will give you the indexing capabilities you're looking for, but you also get to use the range of LINQ functions as well, such as creating a new list of items based on conditions. Plus IList<T> implements IEnumerable<T> so you're going to be able to use foreach to loop through the objects.

e.g. in your class:

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

e.g. usage:

Thing x = business.Things[3];

or

var x = business.Things.Where(t => t.Name == "cori");
江南月 2024-09-15 01:05:36

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

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

尽管在本例中它是公共财产,但使用 getter 和 setter 可以提高可读性并有助于防止意外行为。如果您在循环中访问对象变量并不重要,您应该继续使用 GetThing 约定。

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

注意:它通常被认为是保持对象变量私有并为所有语言使用 getters/setters 的良好风格

C++ 风格指南

C# 风格指南

您可以也对问题“c# 类中的类的 getter 和 setter 感兴趣< /a>”

There are two things to note here. First is that you want to keep object variables private and use getters and setters to access them. This prevents the user from accidentally changing or modifying object variables.

Secondly, it is considered a good naming convention where the terms get/set must be used where an attribute is accessed directly. This helps improve readability.

Although it is a public property in this case, the use of getters and setters improve readability and help prevents unexpected behavior. It doesn't matter if you are accessing the object variables within a loop, you should continue to use the GetThing convention.

Finally if you are accessing the variables from within the object, you don't need to use the getter or setter.

NOTE: Its generally considered good style to keep object variables private and use getters/setters for all languages

C++ style guidelines

C# style guidelines

You may also be interested in the question "getter and setter for class in class c#"

无所谓啦 2024-09-15 01:05:36

如果我不得不猜测,我会说该开发人员习惯了 Java 等其他语言,并且不完全了解 C# 中的标准实践。 “get[Property]”术语在 Java、javascript 等中使用非常频繁。C# 用属性和索引器替换了它。属性与 getter 和 setter 一样强大,但更易于编写和使用。在 C# 中,您通常看到“Get[something]”的唯一情况是:

  • 该操作可能非常昂贵,以至于您确实想要了解这不是简单的成员访问这一事实(例如 GetPrimeNumbers()< /code>),或者
  • 您的集合实际上包含多个索引集合。 (例如GetRow(int i)GetColumn(int i))。即使在这种情况下,更常见的做法是简单地将每个索引集合作为其自身的属性公开,该属性属于索引类型(“table.Rows[2]”)。

如果您for循环中访问这些值,则该集合应该实现IEnumerable,这将使您能够访问LINQ方法和foreach 构造。如果您仍然需要基于索引的 getter,您应该考虑使用您自己的接口,该接口扩展了 IEnumerable,但还提供了:

T this[int i] { get; }

这样,您就不会给消费者留下这样的印象:他们可以添加删除此集合中的对象。

更新

我知道这主要是一个风格问题,这是有争议的,但我真的认为GetThings解决方案不是正确的做事方式。以下策略虽然需要更多工作,但更符合标准 .NET 类和框架的设计方式:

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

If I had to guess, I'd say that this developer was used to some other language like Java, and wasn't fully aware of standard practice in C#. The "get[Property]" nomenclature is very heavily used in Java, javascript, etc. C# replaces this with properties and indexers. Properties are every bit as powerful as getters and setters, but are easier to write and use. The only time you typically see "Get[something]" in C# is if:

  • The operation is likely to be expensive enough that you really want to drive home the fact that this is no simple member access (e.g. GetPrimeNumbers()), or
  • Your collection actually includes multiple indexed collections. (e.g. GetRow(int i) and GetColumn(int i)). Even in this case, it's more common to simply expose each of these indexed collections as a property unto itself, which is of an indexed type ("table.Rows[2]").

If you are only accessing these values in for loops, the collection should implement IEnumerable<Thing>, which would give you access to LINQ methods and the foreach construct. If you still need to have indexed-based getters, you should consider using your own interface which extends IEnumerable<T>, but additionally provides:

T this[int i] { get; }

This way, you don't give consumers the impression that they can Add and Remove objects in this collection.

Update

I know this is mostly a matter of style, which is subject to debate, but I really think the GetThings solution is not the correct way to do things. The following strategy, while it takes a little more work, is far more in keeping with the way that the standard .NET classes and frameworks are designed:

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

Using the code above might look something like this:

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
李白 2024-09-15 01:05:36

就像其他答案所指出的那样,这是限制对数组(或列表)本身的访问的问题。

一般来说,您不希望类的客户端能够直接修改数组本身。隐藏基础列表的实现还允许您将来更改实现,而不会影响使用该类的任何客户端代码。

Like the other answers have indicated, it's an issue of restricting access to the array (or list) itself.

In general, you don't want clients of the class to be able to directly modify the array itself. Hiding the implementation of the underlying list also allows you to change the implementation in the future without affecting any client code that uses the class.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文