Создание метода расширения с использованием CodeDOM - PullRequest
3 голосов
/ 10 июня 2011

Я пытаюсь создать метод расширения с использованием CodeDOM. Похоже, что они не поддерживаются, и использование ExtensionAttribute (которое C # использует внутри для обозначения методов расширения) недопустимо.

Можно использовать трюк для указания модификатора this, но как мне сделать содержащий класс static, чтобы код действительно компилировался?

Поскольку static является концепцией C #, она не раскрывается через API CodeDOM. И установка TypeAttributes на TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.Public не работает, потому что

абстрактный класс не может быть изолированным или статическим

Как мне сделать метод расширения для компиляции?

Ответы [ 4 ]

6 голосов
/ 10 июня 2011

Я почти уверен, что вы ищете:

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

Однако, похоже, это не работает.Интересно, что:

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

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

Но когда вы идете и выводите его, никаких изменений не происходит, хотя свойство Attributes явно меняется с 0x00005002 на 0x00006003.

По MicrosoftПодключить это невозможно :

Спасибо за сообщение об этом.К сожалению, не похоже, что мы можем поддерживать статические классы для 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

, который компилируется.

2 голосов
/ 01 декабря 2011

Немного убрал хак, предоставленный Sixlettervariables: поместил его в статический метод, как упоминалось в обсуждении.

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));
}
1 голос
/ 10 июня 2011

Вместо прямой компиляции CodeCompileUnit вы можете получить исходный код, заменить class Extensions на static class Extensions и скомпилировать этот код.

0 голосов
/ 10 апреля 2017

Вы можете заставить свой код компилировать в точности так, как вам нужно, преобразовав его непосредственно в строку, а затем взломав его:

    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"));
        }
    }
...