我是c#中扩展方法的粉丝,但还没有成功地将扩展方法添加到静态类中,比如Console。
例如,如果我想添加一个名为“WriteBlueLine”的扩展到控制台,这样我就可以:
Console.WriteBlueLine("This text is blue");
我尝试通过添加一个本地的公共静态方法,并将Console作为“this”参数…但是不行!
public static class Helpers {
public static void WriteBlueLine(this Console c, string text)
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine(text);
Console.ResetColor();
}
}
这没有添加'WriteBlueLine'方法控制台…我做错了吗?或者要求不可能的事情?
是的,在有限的意义上。
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的每个方法编写一个代理静态方法。控制台。这并不一定是一件坏事,因为你可以添加这样的内容:
public static void WriteLine(String x)
{ System.Console.WriteLine(x.Replace("Fck","****")); }
or
public static void WriteLine(String x)
{
System.Console.ForegroundColor = ConsoleColor.Blue;
System.Console.WriteLine(x);
}
它的工作方式是你将一些东西钩到标准的WriteLine中。它可以是行数或坏词过滤器或其他什么。只要在命名空间中指定Console,就说WebProject1,然后导入命名空间System, WebProject1。控制台将被选择在系统之上。控制台作为命名空间WebProject1中的这些类的默认值。这段代码将会打开所有的控制台。如果你没有指定System.Console.WriteLine,则WriteLine调用为蓝色。
不可能编写一个扩展方法,但是可以模拟您所要求的行为。
using FooConsole = System.Console;
public static class Console
{
public static void WriteBlueLine(string text)
{
FooConsole.ForegroundColor = ConsoleColor.Blue;
FooConsole.WriteLine(text);
FooConsole.ResetColor();
}
}
这将允许你在其他类中调用Console.WriteBlueLine(fooText)。如果其他类希望访问Console的其他静态函数,则必须通过它们的名称空间显式引用它们。
如果你想把所有的方法都放在一个地方,你总是可以把所有的方法都添加到替换类中。
所以你会得到
using FooConsole = System.Console;
public static class Console
{
public static void WriteBlueLine(string text)
{
FooConsole.ForegroundColor = ConsoleColor.Blue;
FooConsole.WriteLine(text);
FooConsole.ResetColor();
}
public static void WriteLine(string text)
{
FooConsole.WriteLine(text);
}
...etc.
}
这将提供你正在寻找的那种行为。
*注意控制台将必须通过您放入它的命名空间添加。
你能在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 above you could have this:
(null as Console).WriteBlueLine(...); // as oppose to Console.WriteBlueLine(...)
现在为什么我选择调用默认构造函数作为一个例子,为什么我不只是返回新的T()在第一个代码片段而不做所有的表达式垃圾?
今天是你的幸运日,因为你有一个2。任何高级的。net开发人员都知道,new T()很慢,因为它生成了对System的调用。激活器,它在调用默认构造函数之前使用反射获取默认构造函数。该死的微软!
然而,我的代码直接调用对象的默认构造函数。
静态扩展将比这更好,但紧急时刻需要紧急措施。
我真的不明白人们认为他们能从扩展静态类中得到什么……
仅仅做这样的事情,你会牺牲什么?
public static class MyConsole
{
public static void WriteBlueLine(string text)
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine(text);
Console.ResetColor();
}
}
//...
MyConsole.WriteBlueLine("I'm so blue...");
Console.WriteLine("...and I'm not.");
这是最小的额外输入工作,作为奖励,它保持事情透明…
毕竟,即使是常规的扩展方法也只是helper方法的简写。它不允许你对一个类(实例)做任何常规方法做不到的事情。
虽然Console的方法是静态的,但它的静态方法Write()和WriteLine()只是分别将调用重定向到Console. out .Write()和Console. out .WriteLine()。Out是一个实例,其类型派生自抽象类TextWriter。这使得为TextWriter定义扩展方法成为可能:
public static class ConsoleTextWriterExtensions
{
public static void WriteBlueLine(this TextWriter writer, string text)
{
Console.ForegroundColor = ConsoleColor.Blue;
writer.WriteLine(text);
Console.ResetColor();
}
public static void WriteUppercase(this TextWriter writer, string text)
{
writer.Write(text.ToUpper());
}
}
然后可以像这样调用该方法:
Console.Out.WriteBlueLine();
最好的部分是标准错误流实例Console的类型。错误也源于TextWriter,这使得相同的扩展方法也可用于控制台。错误:
Console.Error.WriteBlueLine();
如果您已经定义了像WriteTable()这样的扩展方法(用于将表写入控制台),那么这可能非常有用,因为您还可以将它用于错误流或TextWriter的任何其他对象。
新版本的c#甚至可以用using static语句来获得控制台的红色。前缀:
using static System.Console;
Out.WriteBlueLine("A blue line");
Error.WriteBlueLine("A blue line");