我是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'方法控制台…我做错了吗?或者要求不可能的事情?


当前回答

以下内容作为对tvanfosson回答的编辑被拒绝。我被要求把它作为我自己的答案。我使用了他的建议并完成了ConfigurationManager包装器的实现。原则上我只是填了…在tvanfosson的回答中。

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

public static class ConfigurationManagerWrapper
{
    public static NameValueCollection AppSettings
    {
        get { return ConfigurationManager.AppSettings; }
    }

    public static ConnectionStringSettingsCollection ConnectionStrings
    {
        get { return ConfigurationManager.ConnectionStrings; }
    }

    public static object GetSection(string sectionName)
    {
        return ConfigurationManager.GetSection(sectionName);
    }

    public static Configuration OpenExeConfiguration(string exePath)
    {
        return ConfigurationManager.OpenExeConfiguration(exePath);
    }

    public static Configuration OpenMachineConfiguration()
    {
        return ConfigurationManager.OpenMachineConfiguration();
    }

    public static Configuration OpenMappedExeConfiguration(ExeConfigurationFileMap fileMap, ConfigurationUserLevel userLevel)
    {
        return ConfigurationManager.OpenMappedExeConfiguration(fileMap, userLevel);
    }

    public static Configuration OpenMappedMachineConfiguration(ConfigurationFileMap fileMap)
    {
        return ConfigurationManager.OpenMappedMachineConfiguration(fileMap);
    }

    public static void RefreshSection(string sectionName)
    {
        ConfigurationManager.RefreshSection(sectionName);
    }
}

其他回答

不。扩展方法需要对象的实例变量(值)。但是,您可以围绕ConfigurationManager接口编写一个静态包装器。如果实现包装器,则不需要扩展方法,因为可以直接添加方法。

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

      .....

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

不。扩展方法定义需要所扩展类型的实例。这是不幸的;我不知道为什么需要……

虽然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");

您可以使用null类型转换使其工作。

public static class YoutTypeExtensionExample
{
    public static void Example()
    {
        ((YourType)null).ExtensionMethod();
    }
}

扩展:

public static class YourTypeExtension
{
    public static void ExtensionMethod(this YourType x) { }
}

YourType:

public class YourType { }

你能在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的调用。激活器,它在调用默认构造函数之前使用反射获取默认构造函数。该死的微软! 然而,我的代码直接调用对象的默认构造函数。

静态扩展将比这更好,但紧急时刻需要紧急措施。