我们正在创建自己的代码来自动生成 CRUD 编码,我们需要生成一个用于 WPF 的类。为此,我们需要创建具有字段/属性作为依赖对象的类。我们如何在 .Net 3.5 中使用 CodeDom 实现这一点?
问问题
573 次
2 回答
1
摘要:用依赖注入模式代码替换依赖项,使您的类更易于测试和重用
摘要:本文解释了如何使用 CodeDOM 动态生成代码并使用动态代码编译来构建它。它还解释了如何应用自定义属性。
于 2009-08-20T14:27:43.620 回答
0
您可以使用以下内容动态生成依赖对象,其依赖属性来自字典。
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Reflection;
using System.Windows;
using Microsoft.CSharp;
namespace WpfApplication1
{
public class DependencyPropertyGenerator
{
public static Type Generate(Dictionary<string, Type> typeDef)
{
var codeCompileUnit = new CodeCompileUnit();
var codeNamespace = new CodeNamespace("Generated");
codeNamespace.Imports.Add(new CodeNamespaceImport("System"));
codeNamespace.Imports.Add(new CodeNamespaceImport("System.Windows"));
var codeTypeDeclaration = new CodeTypeDeclaration("DataObject")
{
IsClass = true,
TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed
};
codeTypeDeclaration.BaseTypes.Add(new CodeTypeReference(typeof (DependencyObject)));
codeNamespace.Types.Add(codeTypeDeclaration);
codeCompileUnit.Namespaces.Add(codeNamespace);
AddProperties(codeTypeDeclaration, typeDef);
return CompileAssembly(codeCompileUnit);
}
public static void AddProperties(CodeTypeDeclaration targetClass, Dictionary<string, Type> typeDef)
{
foreach (var pair in typeDef)
{
var dpProperty = new CodeMemberField
{
Name = pair.Key + "Property",
Attributes = MemberAttributes.Public | MemberAttributes.Static,
Type = new CodeTypeReference("DependencyProperty"),
InitExpression = new CodeMethodInvokeExpression(
new CodeTypeReferenceExpression("DependencyProperty"),
"Register",
new CodePrimitiveExpression(pair.Key),
new CodeTypeOfExpression(pair.Value),
new CodeTypeOfExpression(targetClass.Name),
new CodeObjectCreateExpression(typeof (PropertyMetadata),
new CodeDefaultValueExpression(new CodeTypeReference(pair.Value))))
};
targetClass.Members.Add(dpProperty);
var clrProperty = new CodeMemberProperty
{
Name = pair.Key,
Type = new CodeTypeReference(pair.Value),
Attributes = MemberAttributes.Public | MemberAttributes.Final
};
clrProperty.GetStatements.Add(
new CodeMethodReturnStatement(new CodeCastExpression(pair.Value,
new CodeMethodInvokeExpression(null, "GetValue",
new CodeFieldReferenceExpression(null, dpProperty.Name)))
));
clrProperty.SetStatements.Add(
new CodeMethodInvokeExpression(null, "SetValue",
new CodeFieldReferenceExpression(null, dpProperty.Name),
new CodePropertySetValueReferenceExpression()));
targetClass.Members.Add(clrProperty);
}
}
private static Type CompileAssembly(CodeCompileUnit compileUnit)
{
var compilerParameters = new CompilerParameters
{
GenerateExecutable = false,
GenerateInMemory = true
};
var executingAssembly = Assembly.GetExecutingAssembly();
compilerParameters.ReferencedAssemblies.Add(executingAssembly.Location);
foreach (var assemblyName in executingAssembly.GetReferencedAssemblies())
{
compilerParameters.ReferencedAssemblies.Add(Assembly.Load(assemblyName).Location);
}
using (var provider = new CSharpCodeProvider())
{
var compileResults = provider.CompileAssemblyFromDom(compilerParameters, compileUnit);
var compiledAssembly = compileResults.CompiledAssembly;
return compileResults.Errors.Count > 0 ? null : compiledAssembly.GetType("Generated.DataObject");
}
}
}
}
下面是你如何使用它:
[Test]
public void GenerateTest()
{
var typeDictionary = new Dictionary<string, Type>
{
{"Field1", typeof (string)},
{"Field2", typeof (double)},
{"Field3", typeof (decimal)},
{"Field4", typeof (DateTime)},
{"Field5", typeof (float)}
};
var type = DependencyPropertyGenerator.Generate(typeDictionary);
foreach (var fieldName in typeDictionary.Keys)
{
var dp = DependencyPropertyDescriptor.FromName(fieldName, type, type);
Assert.IsNotNull(dp.DependencyProperty);
Assert.AreEqual(dp.DependencyProperty.Name,fieldName);
Assert.AreEqual(dp.DependencyProperty.PropertyType , typeDictionary[fieldName]);
}
}
于 2016-10-16T14:55:03.910 回答