您接受接口作为构造函数参数吗?

发布于 2024-07-12 12:19:27 字数 694 浏览 6 评论 0原文

Krzysztof 的建议是否适用于构造函数? 如果是这样,您如何正确实施?

我们建议使用 Collection、ReadOnlyCollection 或 KeyedCollection 作为输出和属性,并使用接口 IEnumerable、ICollection、IList 作为输入。

例如,

public ClassA
{
    private Collection<String> strings;
    public Collection<String> Strings { get { return strings; } }
    public ClassA(IEnumerable<String> strings)
    {
        this.strings = strings; // this does not compile
        this.strings = strings as Collection<String>; // compiles (and usually runs?)
    }
}

Does Krzysztof's recommendation apply to constructors? If so, how do you implement it properly?

We recommend using Collection, ReadOnlyCollection, or KeyedCollection for outputs and properties and interfaces IEnumerable, ICollection, IList for inputs.

For example,

public ClassA
{
    private Collection<String> strings;
    public Collection<String> Strings { get { return strings; } }
    public ClassA(IEnumerable<String> strings)
    {
        this.strings = strings; // this does not compile
        this.strings = strings as Collection<String>; // compiles (and usually runs?)
    }
}

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

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

发布评论

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

评论(7

短叹 2024-07-19 12:19:27

你应该避免沮丧; 在您的示例中,我建议您的构造函数参数的类型应该与您的成员数据的类型匹配(应该相同)(即任一 Collection IEnumerable)。

或者有 Marc 的解决方案,这是不同的:因为 Marc 的解决方案意味着您的成员数据不仅是不同的类型,而且还是不同的实例(即,如果您修改成员数据,那么您正在修改原始集合的副本,不编辑原始集合本身;类似地,如果在创建副本后修改了原始集合,则您的本地副本/成员数据不包括对原始集合的后续更改)。

You should avoid downcasting; in your example I'd suggest that the type of your contructor parameter should match (should be the same as) the type of your member data (i.e. either Collection<String> or IEnumerable<String>).

Or there's Marc's solution, which is different: because Marc's solution means that your member data isn't only a different type, it's also a different instance (i.e. if you modify the member data, then you're modifying a copy of the original collection, not editing the original collection itself; similarly if the original collection is modified after you make the copy, your local copy/member data doesn't include this subsequent change to the original collection).

一袭白衣梦中忆 2024-07-19 12:19:27

您不应该使用 as 版本 - 您应该接受并存储可重复的内容,例如 IList,或者创建一个新的本地数据集合:

this.strings = new Collection<string>();
foreach(string s in strings) { this.strings.Add(s); }

实际上,我自己会使用 List; 那么你可以这样做(尽管这不是使用 List 的原因):

this.strings = new List<string>(strings);

You shouldn't use the as version - you should either accept and store something repeatable like an IList<T>, or create a new, local collection of the data:

this.strings = new Collection<string>();
foreach(string s in strings) { this.strings.Add(s); }

Actually, I'd use List<T> myself; then you can do (although this isn't the reason to use List<T>):

this.strings = new List<string>(strings);
往日情怀 2024-07-19 12:19:27

我认为如果可能的话应该避免沮丧。 如果该类将输入存储为具体类“Collection”(这意味着该类与“Collection”一起使用,那么我认为只接受“Collection”类型的输入而不是接口对应项更自然。

这将向下转型的责任(如果需要)转移给消费者,如果他向下转型,消费者应该知道他在做什么。

另一方面,我想说接受输入作为接口比具体类更好,因为它允许灵活性。然而,这需要类的内部依赖于接口而不是具体的类(因此在示例中,成员变量将是 IEnumerable 而不是 Collection),

我同意 yapiskan 的观点。 Marc 的解决方案实际上通过创建输入的副本来改变用法,因此责任也发生了变化:

之前:输入始终在使用者和此类之间共享,因此,对输入的更改是在消费者和此类之间“共享”的。消费者和此类

之后:在调用构造函数之后,此类对输入的理解与消费者分离。

I believe that downcasting should be avoided if possible. If the class stores an input as a concrete class "Collection" (which means that this class works with "Collection", then I think the it is more natural to just accept an input of type "Collection" instead of the interface counterpart.

This shift the responsibility of downcasting (if needed) back to the consumer who should know what he is doing if he does downcast it.

On the other hand, I would say that accepting input as interface is better than a concrete class as it allows the flexibility of feeding in mock objects more easily. However, this would require the internals of the class depends on the interface rather than the concrete class (thus in the example, the member variable would be of IEnumerable instead of Collection).

I agree with yapiskan that Marc's solution actually has changed the usage by creating a copy of the input and thus there is a change in responsibility:

Before: the input is shared at all time between the consumer and this class. Therefore, change to the input is "shared" between the consumer and this class

After: this class's understanding of the input is detached from the consumer after the constructor is called.

日裸衫吸 2024-07-19 12:19:27

如果您存储的是 Collection,那么我更喜欢将 ICollection 作为输入。

If what you store is Collection, so I prefer getting ICollection as input.

尾戒 2024-07-19 12:19:27

为什么不接受 IEnumerable 类型的参数并将其强制转换为检索?

public ClassA
{
    private IEnumberable<String> strings;

    public Collection<String> StringCollection {
        get { return (Collection<String>) strings; }
    }

    public ClassA(IEnumerable<String> strings)
    {
        this.strings = strings; 
    }
}

Why not accept a parameter of type IEnumerable<String>and cast it on the retrieval?

public ClassA
{
    private IEnumberable<String> strings;

    public Collection<String> StringCollection {
        get { return (Collection<String>) strings; }
    }

    public ClassA(IEnumerable<String> strings)
    {
        this.strings = strings; 
    }
}
叫思念不要吵 2024-07-19 12:19:27

我有点同意佩奇的观点。

我同意您应该将 IEnumerable 作为输入传递(这样您就支持任何可枚举集合)。

但是你上面对 StringCollection 属性所做的事情对我来说没有意义 - 你正在向下转型,这是行不通的。

-马特

I'd agree with Paige, sort of.

I agree that you should pass IEnumerable as an input (that way you support any enumerable collection).

But what you're doing above with the StringCollection property doesn't make sense to me - you're downcasting, which won't work.

-Matt

清风不识月 2024-07-19 12:19:27

这可能是为了不暴露太多的实现。 理想情况下,如果您正在设计公共 API,您应该只公开最少的实现。 如果您返回完整的 List 接口,那么公共 API 的用户将有多种方式以您可能不希望的方式扰乱类的内部结构。

- - 编辑 - -

This probably all about not exposing too much of your implementation. Ideally if you are designing a public API you should only expose the bare minimum of your implementation. If you return a full List interface there will be loads of ways for a user of the public API to mess with the innards of your classes in ways that you might not have intended.

----edit----

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