我对使用方法与C#中的对象进行交互的不同方式有点困惑,特别是以下几个主要的设计差异和后果:
示例:
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与静态辅助类或扩展方法结合起来会更好?
答案 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 :(得分:12)
无障碍成员:public
,protected
,private
(如果继承则无法访问)
定义:相同的类/结构/接口(可以使用partial
关键字拆分文件)
被称为:object.Method()
在这种情况下,我的意思是静态方法是在他们操作的类中定义的的方法。也就是说,它们与其他类对象一起定义。 (示例代码中MyPoint
类中定义的静态方法。)
我们都知道(或应该知道)这些是什么以及对他们有什么好处,除了说:
之外,我不会详细介绍。实例方法可以访问该类的所有 private
,protected
和public
成员。与static
方法一样。
在大多数情况下,如果要添加大量方法和/或属性,或者显着更改对象的操作,则应继承原始对象(如果可能)。这样,您就可以访问public
的所有protected
和class/struct/interface
成员。
无障碍成员:public
定义:任何类/命名空间
被称为:HelperClass.Method(object)
通过静态帮助程序类方法我暗示本节引用的static
方法的实际定义在实际类定义中不。 (即,使用您的代码示例,类似MyPointHelpers
或类似的类。)
Static Helper类方法只可以访问对象的public
成员(很像扩展方法,我在扩展方法部分之后写了这个部分)。
静态助手类和扩展方法密切相关,在许多情况下是相同的。因此,我将在“扩展方法”部分中将这些好处留给他们。
无障碍成员:public
定义:任何类/命名空间
被称为:object.Method()
扩展方法仅可以访问对象的public
成员。虽然他们出现成为班级成员,但他们不。这限制了它们的用途。 (需要访问任何 private
或protected
成员的方法不应为扩展程序。)
在我看来,扩展方法有三个巨大的好处。
假设您正在开发课程A
,而课程A
中有大约7种方法。你也知道你想要开发一些你不会总是需要的方法,但是如果你做的话,这将是很方便的。您可以使用扩展方法。这些方法将在另一个类中被抽象出来,如果你需要它们,你可以包含(通过类,感谢C#6.0)。您知道以后想要使用的罕见方法,但是您知道并不总是需要。
假设您正在开发程序A
,并且您正在使用DLL Something.Other.C
中的一个类,您不拥有源代码。现在,您希望添加一个与类Something.Other.C
交互的方法,其方式有意义使用实例或常规静态方法,但您没有源,因此您可以'牛逼!输入扩展方法,您可以在其中定义显示的方法,使其成为类Something.Other.C
的成员,但实际 您的的一部分>代码。
假设您开发了自己的库,并将其与许多自己的应用程序一起使用,并且您在开发应用程序X
时意识到您可以真正使用方法Y
再次上课A
。好吧,不是修改类A
的定义(因为那是更多的工作,并且除了应用程序Y
之外你没有使用方法X
),你可以定义一个扩展方法应用程序Y
中仅 的<{1>}, 类A
。现在,您的方法开销严格限制在应用程序X
。应用X
不需要使用此扩展方法。
就性能而言,这取决于方法,他们做什么以及他们如何做。您将受到正在改变的对象上的Z
属性/方法/字段的影响,并且需要衡量其性能。 (如果调用public
而不是public Value
会导致一些重要的验证开销,则实例方法更有意义,因为它可以使用private value
字段或属性。)
答案 2 :(得分:7)
简而言之:
cat.Color = Color.Blue;
cat.Meow();
File.Open(String, FileMode)
是一个返回FileStream
的静态方法。此处无需具有文件的实例。DateTime
课程编写扩展方法的情况并不少见。答案 3 :(得分:1)
最大的区别是:
静态方法和扩展基本相同:Visual Studio允许您调用扩展方法,就像它们是一个实例方法一样,但最后它只是一个带有静态方法的静态方法实例传递给它。
我不了解表现,我不认为你应该过多担心。如果您访问很多属性,实例方法可能会快一些,因为当前实例已经在堆栈中(但我不确定编译器是否以这种方式工作)。
我个人在类中添加方法,如果它们真正属于该类的行为,并使用扩展方法来执行范围更广的操作,例如myClass.ConvertToOtherType()
。