我目前正在开发一个动态编译的API,它基于存储在XML文档中的一些预定义规则。
我很难让CodeDOM使用自定义属性修饰的公共getter和private setter生成属性。
这就是我所追求的:
[Conditional()]
public E3477 E3477 { get; private set; }
但是我得到了这个,这是不好的,因为我不希望公开公开暴露:
[Conditional()]
public E3477 E3477
{
get
{
}
set
{
}
}
这是我正在使用的代码:
var componentRef = string.Format( "E{0}", component.XPathSelectElement( "Element" ).Value );
CodeMemberProperty prop = new CodeMemberProperty();
prop.Name = componentRef;
prop.Type = new CodeTypeReference( componentRef );
prop.HasSet = true;
prop.HasGet = true;
prop.Attributes = MemberAttributes.Public;
CodeAttributeDeclaration conditionalAttr = new CodeAttributeDeclaration( "Conditional" );
prop.CustomAttributes.Add( conditionalAttr );
compositeElementClass.Members.Add( prop );
在CodeDOM中我甚至可以使用它吗?
Stack Overflow上的社区告诉我使用CodeDom并创建程序集而不是使用MSBuild,我最初尝试这样做但是无法使其工作。
**用难以阅读的代码编辑,看它是否可以简化**
string GenerateDataElementsCode()
{
CodeNamespace globalNamespace = new CodeNamespace();
globalNamespace.Imports.Add( new CodeNamespaceImport( string.Format( "{0}.DataElements", _project.Target.RootNamespace ) ) );
CodeCompileUnit unit = new CodeCompileUnit();
unit.Namespaces.Add( globalNamespace );
CodeNamespace ns = new CodeNamespace( string.Format( "{0}.DataElements", _project.Target.RootNamespace ) );
var codesDoc = XDocument.Load( string.Format( @"{0}\{1}", _project.Source.RootPath, _project.Source.UNCL ) );
var doc = XDocument.Load( string.Format( @"{0}\{1}", _project.Source.RootPath, _project.Source.EDED ) );
foreach ( XNode node in doc.Descendants( "DataElement" ) )
{
CodeTypeDeclaration dataElementClass = new CodeTypeDeclaration()
{
Name = string.Format( "E{0}", node.XPathSelectElement( "Identifier" ).Value ),
IsClass = true
};
dataElementClass.Comments.Add( new CodeCommentStatement( node.XPathSelectElement( "Description" ).Value, true ) );
dataElementClass.BaseTypes.Add( "SimpleObject" );
CodeAttributeDeclaration dataElementAttr = new CodeAttributeDeclaration( "DataElement" );
dataElementAttr.Arguments.Add(
new CodeAttributeArgument
{
Name = "",
Value = new CodePrimitiveExpression( node.XPathSelectElement( "Identifier" ).Value )
} );
dataElementAttr.Arguments.Add(
new CodeAttributeArgument
{
Name = "",
Value = new CodePrimitiveExpression( node.XPathSelectElement( "Name" ).Value )
} );
dataElementAttr.Arguments.Add(
new CodeAttributeArgument
{
Name = "",
Value = new CodePrimitiveExpression( node.XPathSelectElement( "Description" ).Value )
} );
CodeAttributeDeclaration dataElementFormatAttr = new CodeAttributeDeclaration( "DataElementFormat" );
dataElementFormatAttr.Arguments.Add(
new CodeAttributeArgument
{
Name = "Cardinality",
Value = new CodePrimitiveExpression( node.XPathSelectElement( "Cardinality" ).Value )
} );
dataElementClass.CustomAttributes.Add( dataElementAttr );
dataElementClass.CustomAttributes.Add( dataElementFormatAttr );
var codes = codesDoc.XPathSelectElements( "SimpleDataElements/SimpleDataElement/CodeLists/CodeList" ).Where( a => a.XPathSelectElement( "../../Code" ).Value == node.XPathSelectElement( "Identifier" ).Value );
if ( codes.Count() > 0 )
{
CodeTypeDeclaration codesClass = new CodeTypeDeclaration( "Codes" );
codesClass.Attributes = MemberAttributes.Static;
codesClass.IsClass = true;
foreach ( XNode codeNode in codes )
{
CodeMemberField con = new CodeMemberField( typeof( string ), string.Format( "Code{0}", codeNode.XPathSelectElement( "Code" ).Value ) );
con.Attributes = MemberAttributes.Public | MemberAttributes.Const;
con.InitExpression = new CodePrimitiveExpression( codeNode.XPathSelectElement( "Code" ).Value );
con.Comments.Add( new CodeCommentStatement( codeNode.XPathSelectElement( "Description" ).Value, true ) );
codesClass.Members.Add( con );
}
dataElementClass.Members.Add( codesClass );
}
ns.Types.Add( dataElementClass );
}
unit.Namespaces.Add( ns );
var provider = new Microsoft.CSharp.CSharpCodeProvider();
using ( var sourceCode = new StringWriter() )
using ( var indentedTextWriter = new IndentedTextWriter( sourceCode, " " ) )
{
// Generate source code using the code provider.
provider.GenerateCodeFromCompileUnit( unit,
indentedTextWriter,
new CodeGeneratorOptions() { BracingStyle = "C" } );
return sourceCode.GetStringBuilder().ToString();
}
}
答案 0 :(得分:0)
当有人说CodeDOM时,我会这样看:
// create compiler
CodeDomProvider provider = CSharpCodeProvider.CreateProvider("C#");
CompilerParameters options = new CompilerParameters();
// add all loaded assemblies
options.ReferencedAssemblies.AddRange(
AppDomain.CurrentDomain.GetAssemblies().Where(item => !item.IsDynamic).Select(item => item.Location).ToArray());
options.GenerateExecutable = false;
options.GenerateInMemory = true;
// source
string source = "using System;namespace Test{public class Test{";
source += "[Conditional()]public E3477 E3477 { get; private set; }";
source += ...
// compile
CompilerResults result = provider.CompileAssemblyFromSource(options, source);
答案 1 :(得分:0)
正如其他人指出的那样,CodeDom本身不支持私有设置器(IIRC,因为它不是适用于CodeDom服务的所有语言的概念)。
大多数解决方案都建议将“ {get; private set;}”明确地硬编码到代码段表达式中,但是如果您需要使用逻辑访问器,这实际上并没有帮助。这是一种相关但不同的方法,可以让我解决类似的问题。虽然不漂亮,但是可以解决问题:
给出一些帮助类,
public static class SnippetGenerator
{
private static CodeDomProvider codeGenProvider = CodeDomProvider.CreateProvider("CSharp");
private static CodeGeneratorOptions codeGenOptions = new CodeGeneratorOptions() { BracingStyle = "C", BlankLinesBetweenMembers = false };
private static StringWriter stringWriter = new StringWriter();
public static string GenerateSnippet(CodeTypeMember member)
{
codeGenProvider.GenerateCodeFromMember(member, stringWriter, codeGenOptions);
string snippet = stringWriter.ToString();
stringWriter.GetStringBuilder().Length = 0;
return snippet;
}
}
然后,您可以将现有的CodeDom属性转换为可通过字符串操作进行后处理的代码段:
CodeMemberProperty componentProperty = new CodeMemberProperty();
... //(build out your property)
// inject private scope onto setter
string propertySnippet = SnippetGenerator.GenerateSnippet(componentProperty);
propertySnippet = propertySnippet.Replace(" set\r\n", " private set\r\n");
CodeSnippetTypeMember propertySnippetMember = new CodeSnippetTypeMember(propertySnippet);
注意:剪裁集可能比包含“ \ r \ n”(根据您的世代/平台设置而定可能有所不同)更好,但可以确保它不是抓取任何不正确的子字符串。选择最适合您的项目的方式。
答案 2 :(得分:-1)
好吧,如果你想使用Codedom Objects,你可以创建一个codememberfield并在其名称中添加一个getter / setter。
CodeMemberfield field = new CodeMemberField
{
Name = "YourPropertyName",
Attributes = MemberAttributes.Public | MemberAttributes.Final,
Type = new CodeTypeReference(typeof(YourClassName)),
};
field.Name += " { get; private set; }";