扩展方法与实例方法与静态类

joh*_*ose 14 c# extension-methods poco static-classes instance-methods

我对使用方法与C#中的对象进行交互的不同方式有点困惑,特别是以下主要设计差异和后果:

  1. 调用实例方法
  2. 在POCO上使用静态类
  3. 创建扩展方法

例:

public class MyPoint
{
    public double x { get; set; }
    public double y { get; set; }

    public double? DistanceFrom(MyPoint p)
    {
        if (p != null)
        {
            return  Math.Sqrt(Math.Pow(this.x - p.x, 2) + Math.Pow(this.y - p.y, 2));
        }
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您只需将方法放在类定义中就可以完成所需的结果,那么为什么POCO与静态辅助类或扩展方法结合起来会更好?

Col*_*lin 16

你问,"如果你只需要在类定义中放置一个方法就可以达到预期的结果,那么为什么POCO与静态辅助类或扩展方法结合起来会更好?"

答案是,这取决于具体情况,以及所讨论的方法是否与您班级的主要关注点直接相关(参见单一责任原则).

下面是一些示例,说明使用每种方法/方法(使用代码示例作为起点)可能是个好主意.

1.实例方法

//This all makes sense as instance methods because you're 
//encapsulating logic MyPoint is concerned with.
public class MyPoint
{
    public double x { get; set; }
    public double y { get; set; }

    public double? DistanceFrom(MyPoint p)
    {
        if (p != null)
            return  Math.Sqrt(Math.Pow(this.x - p.x, 2) + Math.Pow(this.y - p.y, 2));            
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

2.静态类方法 - 错误记录示例.

    //Your class doesn't directly concern itself with logging implmentation;
    //that's something that is better left to a separate class, perhaps
    //a "Logger" utility class with static methods that are available to your class.
    public double? DistanceFrom(MyPoint p)
    {
        try
        {
            if (p != null)
                return  Math.Sqrt(Math.Pow(this.x - p.x, 2) + Math.Pow(this.y - p.y, 2));            
            return null;
        }
        catch(Exception ex)
        {
             //**** Static helper class that can be called from other classes ****
             Logger.LogError(ex);

             //NOTE: Logger might encapsulate other logging methods like...
             //Logger.LogInformation(string s)
             //...so an extension method would be less natural, since Logger
             //doesn't relate to a specific base type that you can create an
             //extension method for.
        }
}
Run Code Online (Sandbox Code Playgroud)

3.扩展方法 - XML序列化示例.

//Maybe you want to make it so that any object can XML serialize itself
//using an easy-to-use, shared syntax.
//Your MyPoint class isn't directly concerned about XML serialization,
//so it doesn't make sense to implement this as an instance method but
//MyPoint can pick up this capability from this extension method.
public static class XmlSerialization
{
    public static string ToXml(this object valueToSerialize)
    {
        var serializer = new XmlSerializer(valueToSerialize.GetType());
        var sb = new StringBuilder();
        using (var writer = new StringWriter(sb))
            serializer.Serialize(writer, valueToSerialize);

        return sb.ToString();
    }
}

//example usage
var point = new MyPoint();
var pointXml = point.ToXml(); //<- from the extension method
Run Code Online (Sandbox Code Playgroud)

经验法则是:

  1. 如果该方法涉及类的主要关注点,请将其放在实例方法中.
  2. 如果您有一个可能对多个类有用的泛型实用程序,请考虑将其放在静态类的方法中.
  3. 如果您的情况类似于2,但与单个基类型相关,或者您认为代码看起来更干净/更简洁而无需单独引用静态类,请考虑扩展方法.

  • 总而言之,我认为这是最好的答案.我的静态类示例有问题,但它可能只是示例本身的一个问题.如果存在业务逻辑或与"Point"本身无关的东西,那么它应该在一个单独的类中.当然,如果可能的话,它应该是一种扩展方法.像`Helper`类这样的静态类被过度使用了.无论它是什么成员,它应该在哪里(无论是对象还是扩展). (2认同)

410*_*one 12

实例/静态方法

可访问成员:public,, (如果继承protected,private则无法访问)

定义:相同的类/结构/接口(可以使用partial关键字拆分文件)

被称为:object.Method()

在这种情况下,我的意思是静态方法在它们操作的类中定义的方法.也就是说,它们与其他类对象一起定义.(MyPoint示例代码中类中定义的静态方法.)

我们都知道(或应该知道)这些是什么以及对他们有什么好处,除了说:

实例方法可以访问所有的 private,protected以及public类的成员.因为这样做static的方法.

在大多数情况下,如果要添加大量方法和/或属性,或者它们会显着更改对象的操作,则应继承原始对象(如果可能).这使您可以访问所有publicprotected成员class/struct/interface.

静态辅助类方法

无障碍会员:public

定义:任何类/命名空间

被称为:HelperClass.Method(object)

通过静态助手类方法我暗示static本节引用的方法的实际定义不在实际的类定义范围内.(即类似MyPointHelpers或类似的类,使用您的代码示例.)

Static Helper类方法只能访问public对象的成员(很像Extension方法,我在扩展方法部分之后写了这个部分).

静态助手类和扩展方法密切相关,并且在许多情况下是相同的.因此,我将在"扩展方法"部分中将这些好处留给他们.

扩展方法

无障碍会员:public

定义:任何类/命名空间

被称为:object.Method()

扩展方法只能访问public对象的成员.虽然他们似乎是班上的成员,但事实并非如此.这限制了它们的用途.(需要访问方法的任何的的privateprotected成员应该不是一个延伸.)

在我看来,扩展方法有三个巨大的好处.

  1. 假设您正在开发类A,并且类中A有大约7种方法.你也知道你想要开发一些你并不总是需要的方法,但如果你做的话,这将是很方便的.您可以使用扩展方法.这些方法将在另一个类中被抽象出来,如果你需要它们,你可以包含(通过类,感谢C#6.0).您知道以后想要使用的罕见方法,但是您知道并不总是需要.

  2. 假设您正在开发程序A,并且您正在使用DLL中的类Something.Other.C,您不拥有源代码.现在,您希望添加一个与类交互的方法,Something.Other.C这种方法对于实例或常规静态方法是有意义的,但是您没有源,所以您不能!输入扩展方法,在这里你可以定义一个方法似乎是类的成员Something.Other.C,但实际上的一部分你的代码.

  3. 假设您开发自己的库,并将其与许多自己的应用程序一起使用,并且您在开发应用程序时X意识到您可以Y在课堂上A再次使用方法.好了,而不是修改类的定义A(因为这是更大量的工作,你不使用方法Y在任何地方,除了应用程序X),你可以定义一个扩展方法Y,A只有在应用程序存在X.现在,您的方法开销严格限制在应用程序中X.应用程序Z不需要具有此扩展方法.

性能

就性能而言,这取决于方法,他们做什么以及他们如何做.您将受到public正在改变的对象上的任何属性/方法/字段的影响,并且需要衡量其性能.(如果调用public Value而不是private value导致一些重要的验证开销,则实例方法更有意义,因为它可以使用private字段或属性.)


Pre*_*cco 7

简而言之:

  1. 实例方法
    • 实例属性就像名词一样.例如cat.Color = Color.Blue;
    • 实例方法就像动词一样.它们应该导致与类的类型相关的动作.例如cat.Meow();
    • 这种方法在C#中很常见.
  2. 静态方法
    • 将此视为辅助方法.
    • 静态方法通常执行与类类型相关的操作...而不是特定实例.
    • 创建类时必须定义静态方法.
    • 示例:File.Open(String, FileMode)是一个返回a的静态方法FileStream.这里不需要有文件的实例.
  3. 扩展方法
    • 将此视为辅助方法.
    • 扩展方法是事后定义的......对于您无法更改的现有第三方类,但希望您可以.
    • 例如:看到人们为DateTime该类编写扩展方法并不罕见.
    • 关于何时/何地应该使用扩展方法的争论并不少见.

参考