正在使用CodeDOM创建扩展方法

本文关键字:创建 扩展 方法 CodeDOM | 更新日期: 2023-09-27 17:59:03

我正在尝试使用CodeDOM创建一个扩展方法。似乎没有任何对它们的支持,并且不允许使用ExtensionAttribute(C#在内部使用它来标记扩展方法)。

可以使用一个技巧来指定this修饰符,但是我如何使包含类static,以便代码真正编译呢?

由于static是一个C#概念,因此它不会通过CodeDOM API公开。将TypeAttributes设置为TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.Public不起作用,因为

抽象类不能被密封或静态

如何使扩展方法进行编译?

正在使用CodeDOM创建扩展方法

我很确定您正在寻找:

var staticClass = new CodeTypeDeclaration("Extensions")
    {
        Attributes = MemberAttributes.Public|MemberAttributes.Static
    };

然而,这似乎并不奏效。有趣的是:

provider.Supports(GeneratorSupport.StaticConstructors);
// True
provider.Supports(GeneratorSupport.PublicStaticMembers);
// True

但是,当您去输出它时,即使Attributes属性明显从0x00005002更改为0x00006003,也不会发生任何更改。

根据Microsoft Connect,这是不可能的:

感谢您的报道。不幸的是,我们似乎无法支持CodeDom的静态类。

原因是CodeDom的设计目标之一是独立于语言,这样为一种语言生成的任何代码都可以很容易地为另一种语言产生。虽然C#中经常使用静态类,但VB并不支持它们。因此,添加对静态类的支持将意味着一些可以为C#编译的代码将无法为VB编译,这与我们的目标背道而驰。

虽然我们无法对此问题采取行动,但我们要求您在未来继续提供反馈,以帮助我们改进。


一个肮脏的解决方法:

var type = new CodeTypeDeclaration("Extensions");
type.Attributes = MemberAttributes.Public;
type.StartDirectives.Add(
    new CodeRegionDirective(CodeRegionMode.Start, "'nstatic"));
type.EndDirectives.Add(
    new CodeRegionDirective(CodeRegionMode.End, String.Empty));

产品:

#region
static
public class Extensions
{
}
#endregion

它编译。

您可以获得源代码,用static class Extensions替换class Extensions并编译该代码,而不是直接编译CodeCompileUnit

稍微清理了sixtlettervariables提供的破解:将其放入静态方法中,如讨论中所述。

public static void MarkAsStaticClassWithExtensionMethods(this CodeTypeDeclaration class_)
{
   class_.Attributes = MemberAttributes.Public;
   class_.StartDirectives.Add(new CodeRegionDirective(
           CodeRegionMode.Start, Environment.NewLine + "'tstatic"));
   class_.EndDirectives.Add(new CodeRegionDirective(
           CodeRegionMode.End, string.Empty));
}

您可以直接将代码转换为字符串,然后对其进行黑客攻击,从而使代码按照您的意愿进行编译:

    private static CodeSnippetTypeMember CreateStaticClass(CodeTypeDeclaration type)
    {
        var provider = CodeDomProvider.CreateProvider("CSharp");
        using (var sourceWriter = new StringWriter())
        using (var tabbedWriter = new IndentedTextWriter(sourceWriter, "'t"))
        {
            tabbedWriter.Indent = 2;
            provider.GenerateCodeFromType(type, tabbedWriter, new CodeGeneratorOptions()
            {
                BracingStyle = "C",
                IndentString = "'t"
            });
            return new CodeSnippetTypeMember("'t't" + sourceWriter.ToString().Replace("public class", "public static class"));
        }
    }