这些问题是关于我之前问过的扩展方法的后续问题。
这些问题是关于我之前问过的扩展方法的后续问题。
当你使用LINQ并希望从一个函数中输出按功能链或管道传递到另一个函数时,它就很有意义。这可以提高代码的可读性,并允许您更优雅地表达概念(无论价值如何)。
它们还允许您在任何您喜欢的类型上给出实例方法的外观,而无需修改该类型的源代码。当合理使用时,这通常有助于提高代码的可读性和表现力。
请注意,像这样的扩展方法调用:
instance.SomeExtensionMethod()
被编译成:
StaticExtensionMethodClass.SomeExtensionMethod(instance);
因此,性能将与任何其他静态方法调用相同。
以下是我在这里回答的内容:
关于扩展方法的实际用途,您可以在不派生新类的情况下向类添加新方法。
请看以下示例:
public class extended {
public int sum() {
return 7+3+2;
}
}
public static class extending {
public static float average(this extended extnd) {
return extnd.sum() / 3;
}
}
Extending
添加了一个名为average的方法到类Extended
中。要获得平均值,你可以调用average
方法,因为它属于extended
类:extended ex = new extended();
Console.WriteLine(ex.average());
参考资料: http://aspguy.wordpress.com/2008/07/03/a-practical-use-of-serialization-and-extension-methods-in-c-30/
关于性能方面,我认为使用扩展方法可以看到改进,因为它们永远不会被动态调度,但这完全取决于动态方法的实现方式。
ExtendUnlimitedCredit(AddVIP(tblCustomer, "Bill Gates"))
对
tblCustomer.AddVIP("Bill Gates").ExtendUnlimitedCredit()
扩展方法使这种转换变得简单。使用“主动语态”代码消除嵌套函数调用通常是一种改进。此外,由于我们的商店锁定了其核心类,因此我们只能在扩展方法之前利用嵌套函数调用。
关于扩展方法的其他优点:
它们使您的函数(由于智能感知)更易发现。如果您提供了描述函数目的和用途的内联标记,智能感知甚至会为发现它的开发人员提供有用的工具提示,描述该方法及其用途(仅需按下点)。未标记为扩展方法的函数不太容易发现,可能不会被使用,结果可能会有人发明自己的版本。
虽然您实际上无法为接口实现方法,但扩展方法提供了一种替代手段,看起来您已经这样做了。
它被用于扩展(添加)现有类的功能,而不实际改变它们。
这可以在LINQ(System.Linq命名空间和其他)如何向所有集合添加大量功能中看到。
扩展方法的另一个有趣用途是当您希望将某些功能添加到一个命名空间下的类中,而不是另一个命名空间。一个具体的例子是添加方法以便于单元测试 - 您不希望它们混杂在您的生产程序集中,但在编写单元测试时它们非常有用。
IList<T>
添加一个扩展方法。string
上添加一个 Reverse()
方法?加上它吧!public static void ThrowIfNull<T>(this T obj, string name) where T : class
{
if(obj == null) throw new ArgumentNullException(name);
}
var foo = source.Where(predicate).OrderBy(selector);
比起以下的代码,这段代码更易读:
var foo = Enumerable.OrderBy(Enumerable.Where(source,predicate),selector);
使用常规方法,要使用第一种方法,它必须是常规实例方法,这将需要更改(例如)IEnumerable<T>
- 这是不可取的。
/// <summary>
/// External Library Code
/// </summary>
namespace ExternalLibrary
{
public class Calculator
{
public int Number1 { get; set; }
public int Number2 { get; set; }
public int Addition()
{
return Number1 + Number2;
}
public int Subtraction()
{
return Number1 - Number2;
}
}
}
--------------------------------------------------------------------------------------
using ExternalLibrary;
using System;
namespace StackOverFlow
{
class Program
{
static void Main(string[] args)
{
Calculator calc = new Calculator()
{
Number1 = 5,
Number2 = 3
};
Console.WriteLine(calc.Addition());
Console.WriteLine(calc.Subtraction());
// Here we want multiplication also. but we don't have access Calculator
// class code, so we can't modify in that.
// In order to achieve this functionality we can use extension method.
Console.WriteLine(calc.Multiplication());
Console.ReadLine();
}
}
/// <summary>
/// Extension Method for multiplication
/// </summary>
public static class CalculatorExtension
{
public static int Multiplication(this Calculator calc)
{
return calc.Number1 * calc.Number2;
}
}
}
我不知道有任何性能影响。当您无法访问源代码并且因此无法直接将方法添加到类中时,使用扩展方法是最合理的选择,并且该方法可以作为函数实现。这涉及到我在您之前的问题中发表的评论,在那里另一个人给出了一个关于“string”类的扩展方法示例,该示例基于字符串是否为有效电子邮件返回布尔值。在我看来,这是不应该使用扩展方法的示例,因为该函数对于字符串类型并不基本。但是,向“string”添加Left(int)和Right(int)函数确实是有意义的。
我使用它们来重用我的对象模型类。我有一堆代表数据库中对象的类。这些类仅在客户端用于显示对象,因此基本用法是访问属性。
public class Stock {
public Code { get; private set; }
public Name { get; private set; }
}
由于这种使用模式,我不想在这些类中拥有业务逻辑方法,因此我将每个业务逻辑都作为扩展方法。
public static class StockExtender {
public static List <Quote> GetQuotesByDate(this Stock s, DateTime date)
{...}
}
这样我就可以使用相同的类来处理业务逻辑和用户界面显示,而不会在客户端上加载不必要的代码。
这个解决方案有趣的地方在于,我的对象模型类是使用Mono.Cecil动态生成的,因此即使我想添加业务逻辑方法也非常困难。我有一个编译器,它读取XML定义文件并生成这些存储在数据库中的对象的存根类。在这种情况下,唯一的方法是扩展它们。