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

时间:2015-05-29 18:24:32

标签: c# extension-methods poco static-classes instance-methods

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

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

    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;
        }
    }
    

    如果你可以通过简单地在类定义中放置一个方法来完成所需的结果,那么为什么POCO与静态辅助类或扩展方法结合起来会更好?

4 个答案:

答案 0 :(得分:16)

你问,&#34;如果你只需在类定义中放置一个方法就可以达到预期的结果,为什么POCO结合静态辅助类或扩展方法更合适?&#34; < / p>

答案是,这取决于具体情况,如果所涉及的方法与您的班级直接相关&#39;主要关注点(见single responsibility principle)。

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

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;
    }
}

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.
        }
}

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

经验法则是:

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

答案 1 :(得分:12)

实例/静态方法

无障碍成员publicprotectedprivate(如果继承则无法访问)

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

被称为object.Method()

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

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

之外,我不会详细介绍。

实例方法可以访问该类的所有 privateprotectedpublic成员。与static方法一样。

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

静态助手类方法

无障碍成员public

定义:任何类/命名空间

被称为HelperClass.Method(object)

通过静态帮助程序类方法我暗示本节引用的static方法的实际定义在实际类定义中。 (即,使用您的代码示例,类似MyPointHelpers或类似的类。)

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

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

扩展方法

无障碍成员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中仅 的<{1>}, A。现在,您的方法开销严格限制在应用程序X。应用X不需要使用此扩展方法。

  4. 效果

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

答案 2 :(得分:7)

简而言之:

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

答案 3 :(得分:1)

最大的区别是:

  • 您可以定义无法更改的对象的扩展
  • 实例方法可以访问私有变量,其中静态方法/扩展不能

静态方法和扩展基本相同:Visual Studio允许您调用扩展方法,就像它们是一个实例方法一样,但最后它只是一个带有静态方法的静态方法实例传递给它。

我不了解表现,我不认为你应该过多担心。如果您访问很多属性,实例方法可能会快一些,因为当前实例已经在堆栈中(但我不确定编译器是否以这种方式工作)。

我个人在类中添加方法,如果它们真正属于该类的行为,并使用扩展方法来执行范围更广的操作,例如myClass.ConvertToOtherType()