随着扩展方法的出现,抽象类的吸引力是否降低了?

发布于 2024-07-14 17:17:01 字数 462 浏览 5 评论 0原文

.NET 中扩展方法的一个有趣的方面是您可以将它们应用到接口。 对我来说,我可以在接口附近定义功能,而无需定义使程序集混乱的抽象类,这似乎很好。

我知道抽象类并没有过时,但是您对在代码中利用这种副作用有何看法?

例子:

public static class IUserExtensions
{
    public static bool IsCurrentUser(this IUser user)
    {
        return (HttpContext.Current.User != null &&
                HttpContext.Current.User.Identity.Name == user.ID.ToString());
    }
}

public interface IUser {
    int ID { get; set; }
}

One interesting aspect of extension methods in .NET is the fact that you can apply them to interfaces. For me, it seems nice that I can define functionality near the interface without defining an abstract class that clutters the assembly.

I know that abstract classes are not obsolete or anything, but how do you feel about utilizing this side effect in your code?

Example:

public static class IUserExtensions
{
    public static bool IsCurrentUser(this IUser user)
    {
        return (HttpContext.Current.User != null &&
                HttpContext.Current.User.Identity.Name == user.ID.ToString());
    }
}

public interface IUser {
    int ID { get; set; }
}

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

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

发布评论

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

评论(11

萌酱 2024-07-21 17:17:01

扩展方法可以让您专注于抽象类实际应该做什么。 在抽象类中实现“实用”代码是一种诱惑,因为即使它可能不是逻辑继承树的一部分,它也会被实现者使用。 扩展方法允许您将这些实用程序方法附加到接口,而不会弄乱您的抽象基类。

编辑

具体来说,我将应用这些准则。

继承

  • 如果行为是基类逻辑行为的一部分,请务必使用
  • 继承;如果行为是横切的(适用于对象层次结构之外的事物),请勿使用继承。 这些将需要重复。

实用程序类

  • 如果行为在逻辑上不属于其所作用的类,则应使用实用程序类(静态类)
  • 。如果实用程序类修改其所作用的对象的内部状态,请勿使用实用程序类。 状态修改应该为对象实现层次结构保留。

扩展方法

  • 确实对扩展方法使用与对实用程序类相同的决策,因为它们会产生更少的摩擦。 如果采用扩展方法感觉不太自然,请不要这样做。
  • 请使用扩展方法向您无法控制的类(例如字符串)添加实用程序。
  • 当行为由其扩展的类使用时,请勿使用扩展方法。 虽然可以这样做,但感觉做作,
  • 不要仅仅因为可以就使用扩展方法。 事实上,除非您必须这样做,否则不要偏离老式的 OOP。 然而,当你不得不这样做时,扩展方法是一个相对有用且无害的决定。

编辑2

关于扩展方法的另一个DO的想法

确实使用扩展方法为某些实现提供自然语言(内部DSL)。 这是一个愚蠢的例子。

int age = getAge();
if (age.IsDraftAge() && !age.IsLegalDrinkingAge())
{
    Console.WriteLine(@"You cannot drink until your birthdate on {0}.
Join the army instead.",
                      age.GetYearWhenGettingDrunkIsOk());
}

What extension methods lets you do is to focus in on what abstract classes should actually be doing. There's a temptation to implement "utility" code in abstract classes because it will be used by implementers even though it may not be part of the logical inheritance tree. Extension methods let you attach these utility methods to the interface without cluttering up your abstract base classes.

EDIT

Specifically, I would apply these guidelines.

Inheritance

  • DO use inheritance if the behavior is part of the logical behavior of the base class
  • DO NOT use inheritance if the behavior is cross-cutting (applies to things outside of your object hierarchy). These will require duplication.

Utility Classes

  • DO use utility classes (static classes) if the behavior does not logically belong to the class it's acting on
  • DO NOT use utility classes if they modify the internal state of the object it's acting on. State modification should be reserved only for the object implementation hierarchy.

Extension Methods

  • DO use the same decision for extension methods as you would for utility classes when they create less friction. If adopting extension methods feels less natural, don't do it.
  • DO use extension methods to add utility to classes you don't have control over (like string).
  • DO NOT use extension methods when the behavior is consumed by the class it is extending. While it is possible to do it, it feels contrived
  • DO NOT use extension methods just because you can. In fact don't deviate from good old fashioned OOP unless you have to. When you have to, however, extension methods are a relatively uesful and harmless decision to make.

EDIT 2

Thought of another DO for extension methods

DO use extension methods to provide a natural language (internal DSL) for certain implementations. Here's a silly example.

int age = getAge();
if (age.IsDraftAge() && !age.IsLegalDrinkingAge())
{
    Console.WriteLine(@"You cannot drink until your birthdate on {0}.
Join the army instead.",
                      age.GetYearWhenGettingDrunkIsOk());
}
油饼 2024-07-21 17:17:01

我已经多次使用这个功能 - 事实上,这个功能是专门为了装饰接口而不修改它们而创建的,因此是 LINQ。 LINQ(至少对于对象)的所有优点都基于 IEnumerable的扩展方法。

但是,我不认为扩展方法可以在您需要时以任何方式取代抽象基类。 扩展方法无法访问扩展类的私有状态 - 扩展方法看起来像实例,但仍然是静态的。

扩展方法和抽象基类解决两种不同类型的问题,以及使用这些范例的选择不应该互相依赖。

我对你的标题问题的回答是:不,扩展方法的存在不会降低抽象基类的吸引力。 如果有人认为扩展方法的存在使抽象基类的吸引力降低,那么人们一开始就没有正确使用抽象基类。

I have used this functionality several times - and in fact, this functionality was created specifically for the purpose of decorating interfaces without modifying them, hence LINQ. All the goodness that is LINQ (to Objects at least) is based on extension methods to IEnumerable<T>.

However, I don't feel that extension methods in any way replace abstract base classes for when you need them. Extension methods cannot access the extended class's private state - extension methods look like instances, but are still static.

Extension methods and abstract base classes solve two different types of problems, and the choice to use either of these paradigms should not depend on each other.

My answer to your title question is thus: No, the existence of Extension Methods do not make Abstract Base Classes less attractive. If one believes that the existence of Extension Methods makes Abstract Base Classes less attractive, then one wasn't using Abstract Base Classes correctly in the first place.

南笙 2024-07-21 17:17:01

不,它会减少抽象类的一些误用。

抽象类应该包含子类可以覆盖的默认实现/行为。 如果考虑得当,这意味着您可以仅覆盖该类的单个行为,并使用其余行为的默认值。 扩展方法提供了与此完全不同的东西。

No, it will reduce some missuses of abstract classes.

An abstract class should contain default implementations/behaviors the subclasses can override. If factored appropriately, this means you could override just a single behavior of the class, and work with the defaults for the rest. Extension methods provide something really different to this.

森末i 2024-07-21 17:17:01

我确实喜欢扩展方法,因为它使我能够在 IList 上定义 Find(Predicate)、Remove(Predicate) 等,而我一直缺少这些功能。 我认为你不能说它们是抽象类的替代品。

我还定义了扩展方法来添加通用行为。 我喜欢对象上的 ToJson 扩展方法或非常方便的 ToXml。

我对你的示例遇到的唯一问题是我总是将 IsCurrentUser 视为属性而不是方法,可惜我们没有扩展属性。 但我挑剔

他们完全不相关。 当我想要对其他人将实现或继承的行为进行建模时,我使用抽象类。

I do like extension methods because it has given me the ability to define Find(Predicate), Remove(Predicate) etc on IList<T> which I have been missing. I do not think you can say they are a replacement for abstract classes.

I have also defined extension methods to add generic behavior. I love my ToJson extension method on object or ToXml quite handy.

The only problem I have with your example is I always look IsCurrentUser as a property not a method and alas we have no extension properties. But I'm nitpicking

They are completly unrelated. I use an abstract class when I want to model a behavior, that others will implement or inherit.

仲春光 2024-07-21 17:17:01

不,抽象类的吸引力同样不减。 抽象类为对象层次结构提供了适当的范例。

仅当您需要向现有类添加实例方法但无法直接修改代码时,扩展方法才真正有用。

No, abstract classes are not less attractive. Abstract classes provide the proper paradigm for object hierarchies.

Extension methods are only really useful if you need to add instance methods to an already existing class but can't modify the code directly.

撩人痒 2024-07-21 17:17:01

扩展方法很好,但您不能将它们或它们的用法与抽象类进行比较。 不要忘记封装是什么,它是OOP的支柱之一。 ..

Extension methods are nice, but you can't compare them or their usage to abstract classes. Don't forget what encapsulation is, it's one of the pillar of OOP...

淡淡離愁欲言轉身 2024-07-21 17:17:01

我认为这取决于您的使用 -

如果您主要关心的是重构以最大限度地减少程序集中源文件和/或类的数量,那么是的,扩展方法绝对是正确的选择,并且抽象类可能最终会被使用较少的。

然而,对于那些更关心抽象类在概念上代表什么的人来说,并没有太大变化。 在代码组织上下文中,将“public int getCalories()”放入抽象类“Food”中仍然有意义,因为对于吃它的人(使用食物子类的代码)来定义多少是愚蠢的它有卡路里。

I think it depends on your use-

If your main concern is refactoring to minimize the number of source files and/or classes in an assembly, then yes, extension methods are definitely the way to go, and abstract classes will probably end up being used less.

However, for those who care more about what abstract classes represent conceptually, not much has changed. It still makes sense in a code-organizational context to put "public int getCalories()" in abstract class "Food", as it'd be silly for the person eating it (the code using a subclass of food) to define how many calories it has.

桃气十足 2024-07-21 17:17:01

一句话:是的。 由于抽象类对未来的实现有很大影响,一般建议似乎是创建实现接口的抽象类(例如 DBDataReader : IDataReader)。 只要方法不需要访问对象的内部状态,我认为没有理由不将其呈现为扩展方法。 您无需支付任何费用即可获得功能。

In a word: Yes. Due to the fact that abstract classes impose a lot on future implementations, general advice seems to be to create abstract classes that implement interfaces (e.g. DBDataReader : IDataReader). So long as a method does not require access to the internal state of an object, I see no reason not to render it as an extension method. You get the functionality without the cost.

与君绝 2024-07-21 17:17:01

我认为在某些情况下这绝对是个好主意。 Linq 是一个很好的例子来说明其优点,但还有另一个优点:流。

Stream 是一个抽象类的全部原因是因为它们必须支持 BeginRead、ReadByte 等方法。Stream 可以是一个接口,所有这些方法都可以是扩展方法。 这使得可以执行诸如从非流类继承并添加流功能之类的操作,并使添加潜在有用的流方法(例如“将流内容转储到内存缓冲区”)变得(更)自然。

I think there are absolutely cases where this is a good idea. Linq is a great example of the benefits, but there is another: streams.

The whole reason streams are an abstract class is because they had to support methods like BeginRead, ReadByte, etc. Stream could be an interface, and all of those methods could be extension methods instead. This would make it possible to do things like inherit from a non-stream class and add stream functionality, and make it (more) natural to add potentially useful stream methods like 'dump stream contents to memory buffer'.

忘东忘西忘不掉你 2024-07-21 17:17:01

如果您不需要从扩展方法访问受保护的字段,那么据我所知这是正确的方法,因为您可以继承多个接口并以这种方式获取所有相关的扩展(而您只能从单个抽象类派生)。

If you don't need to access protected fields from the extension method, then it's AFAIK the way to go, since you can inherit multiple interfaces and get all the related extensions this way (while you can only derive from a single abstract class).

半寸时光 2024-07-21 17:17:01

我没有使用过 .NET 2.0 之后的任何东西,所以我不知道你可以做到这一点。 我觉得很奇怪; 接口不用于实现。 我会觉得这很令人困惑。 另外,您显示的示例是一个类,而不是一个接口。

I have not used anything past .NET 2.0, so I had no idea you could do that. Seems weird to me; interfaces are not for implementations. I would find that confusing. Also, the example that you show is a class, not an interface.

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