Creating extension method using CodeDOM
I'm trying to create an extension method using CodeDOM. There doesn't seem to be any support for them and using ExtensionAttribute
(which C# uses internally to mark extension methods) is not allowed.
It's possible to use a trick to specify the this
modifier, but how do I make the containing class static
, so that the code actually compiles?
Since static
is a C# concept, it开发者_开发知识库's not exposed through the CodeDOM API. And setting TypeAttributes
to TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.Public
doesn't work, because
an abstract class cannot be sealed or static
How do I make the extension method to compile?
I'm pretty sure you're looking for:
var staticClass = new CodeTypeDeclaration("Extensions")
{
Attributes = MemberAttributes.Public|MemberAttributes.Static
};
However, this appears not to work. Interestingly enough:
provider.Supports(GeneratorSupport.StaticConstructors);
// True
provider.Supports(GeneratorSupport.PublicStaticMembers);
// True
But yet when you go and output it, no changes even though the Attributes property clearly changes from 0x00005002
to 0x00006003
.
Per Microsoft Connect this is not possible:
Thanks for reporting this. Unfortunately, it doesn't look like we can support static classes for CodeDom.
The reason is that one of the design goals of CodeDom is to be language-independent, so that any code generated for one language can easily be generated for a different language. While static classes are used often in C#, VB does not support them. Therefore, adding support for static classes will mean that some code that can compile for C# won't be compilable for VB, which goes against our goals.
While we can't act on this issue, we ask that you please continue to provide feedback in the future to help us improve.
A dirty workaround:
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));
Produces:
#region
static
public class Extensions
{
}
#endregion
Which compiles.
Instead of compiling the CodeCompileUnit
directly, you could get the source code, replace class Extensions
with static class Extensions
and compile that code.
Cleaned up the hack provided by sixlettervariables a little: placed it into a static method, as mentioned in the discussion.
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));
}
You can get your code to compile exactly how your want it by converting it directly into a string, and then hacking it:
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"));
}
}
精彩评论