CSharp - 我可以向现有的静态类添加扩展方法?

  显示原文与译文双语对照的内容

我是 C# 中的扩展方法的爱好者,但是没有成功地将扩展方法添加到静态类,比如控制台。

例如如果我想向控制台添加一个扩展名为'writeblueline',这样我就可以:


Console.WriteBlueLine("This text is blue");

我通过添加一个本地的公共静态方法来尝试这个,控制台作为'这个'参数。 但没有骰子 !


public static class Helpers {
 public static void WriteBlueLine(this Console c, string text)
 {
 Console.ForegroundColor = ConsoleColor.Blue;
 Console.WriteLine(text);
 Console.ResetColor();
 }
}

这没有将'writeblueline'方法添加到控制台。。 我做错了? 或者是找不到可能的?

时间:

否。扩展方法需要对象的实例。 但是,你可以在 ConfigurationManager 接口上编写一个静态包装器。 如果实现包装器,则不需要扩展方法,因为可以直接添加方法。


 public static class ConfigurationManagerWrapper
 {
 public static ConfigurationSection GetSection( string name )
 {
 return ConfigurationManager.GetSection( name );
 }

. . ...

 public static ConfigurationSection GetWidgetSection()
 {
 return GetSection("widgets" );
 }
 }

你能将静态扩展添加到 C# 中的类? 不,但你可以这样做:


public static class Extensions
{
 public static T Create<T>(this T @this)
 where T : class, new()
 {
 return Utility<T>.Create();
 }
}

public static class Utility<T>
 where T : class, new()
{
 static Utility()
 {
 Create = Expression.Lambda<Func<T>>(Expression.New(typeof(T).GetConstructor(Type.EmptyTypes))).Compile();
 }
 public static Func<T> Create { get; private set; }
}

下面是它的工作原理。尽管你不能在技术上编写静态扩展方法,但是这里代码利用了扩展方法中的漏洞。 这个漏洞是你可以在空对象上调用扩展方法而不获取空异常( 除非你通过 @this). 访问任何内容)

下面是你使用这个的方法:


 var ds1 = (null as DataSet).Create();//as oppose to DataSet.Create()
//or
 DataSet ds2 = null;
 ds2 = ds2.Create();

//using some of the techniques 上面 you could have this:
 (null as Console).WriteBlueLine(...);//as oppose to Console.WriteBlueLine(...)

现在我为什么选择默认构造函数作为一个示例,为什么不在第一个代码Fragment中返回新的T(),而不做所有的表达式垃圾? 今天你的幸运日,因为你得到了 2. 就像任何高级. NET 开发人员所知,新的T() 是缓慢的,因为它生成一个对 System.Activator的调用,它使用反射来在调用它之前获取默认构造函数。 死的你微软但是我的代码直接调用对象的默认构造函数。

静态扩展会比这个好,但有时候会调用绝望的度量。

我认为MS在这里犯了一个错误。

他们的决定没有意义,迫使程序员编写一个毫无意义的包装类。

下面是一个很好的例子: 尝试扩展静态MS单元测试类断言: 我想要 1个断言方法 AreEqual(x1,x2)

惟一的方法是指向不同的类,或者在 100个不同的断言方法中编写一个包装器。 ? !

如果决定允许扩展实例,我认为不允许使用静态扩展。 一旦可以扩展实例,关于分段库的参数就不成立了。

可以使用自定义命名空间和相同的类名添加静态类:


using CLRConsole = System.Console;

namespace ExtensionMethodsDemo
{
 public static class Console
 {
 public static void WriteLine(string value)
 {
 CLRConsole.WriteLine(value);
 }

 public static void WriteBlueLine(string value)
 {
 System.ConsoleColor currentColor = CLRConsole.ForegroundColor;

 CLRConsole.ForegroundColor = System.ConsoleColor.Blue;
 CLRConsole.WriteLine(value);

 CLRConsole.ForegroundColor = currentColor;
 }

 public static System.ConsoleKeyInfo ReadKey(bool intercept)
 {
 return CLRConsole.ReadKey(intercept);
 }
 }
 class Program
 {
 static void Main(string[] args)
 {
 try
 {
 Console.WriteBlueLine("This text is blue"); 
 }
 catch (System.Exception ex)
 {
 Console.WriteLine(ex.Message);
 Console.WriteLine(ex.StackTrace);
 }

 Console.WriteLine("Press any key to continue...");
 Console.ReadKey(true);
 }
 }
}

不能将静态方法添加到类型。 只能将( 伪- ) 实例方法添加到类型的实例。

this 修饰符的目的是告诉 C# 编译器通过实例的left-side . 作为静态/扩展方法的第一个参数。

在将静态方法添加到类型时,第一个参数没有要传递的实例。

是的,在有限的意义上。


public class DataSet : System.Data.DataSet
{
 public static void SpecialMethod() { }
}

这里操作有效,但控制台不存在,因为它是静态的。


public static class Console
{ 
 public static void WriteLine(String x)
 { System.Console.WriteLine(x); }

 public static void WriteBlueLine(String x)
 {
 System.Console.ForegroundColor = ConsoleColor.Blue;
 System.Console.Write(.x); 
 }
}

这是因为它不在同一个命名空间上。 问题是你必须为 System.Console 拥有的每种方法编写一个代理静态方法。 你可以添加类似这样的内容,这并不是一件坏事:


 public static void WriteLine(String x)
 { System.Console.WriteLine(x.Replace("Fck","****")); }

或者


 public static void WriteLine(String x)
 {
 System.Console.ForegroundColor = ConsoleColor.Blue;
 System.Console.WriteLine(x); 
 }

它的工作方式是将一些东西插入标准的WriteLine 。 它可能是行计数或者错误的字过滤器,或者别的。 当你只是在你的名称空间指定控制台说WebProject1并导入命名空间系统, WebProject1.Console 将选择 System.Console WebProject1作为类的默认名称空间。 所以这段代码将把所有的Console.WriteLine 调用变成蓝色,因为你没有指定 System.Console.WriteLine 。

...