Как мы используем .Net CodeDom для создания объекта зависимостей? - PullRequest
1 голос
/ 20 августа 2009

Мы создаем наш собственный код, сгенерированный для автоматизации кодирования CRUD, и нам нужно создать класс для использования с WPF. Для этого нам нужно создать класс с полями / свойствами в качестве объектов зависимости. Как нам сделать это с CodeDom в .Net 3.5?

Ответы [ 2 ]

1 голос
/ 20 августа 2009

Статья - Три способа внедрения внедрения зависимостей в приложениях .NET

РЕЗЮМЕ: Заменить зависимости на Код шаблона зависимости зависимостей сделать ваши занятия проще для тестирования и повторное использование

Генерация динамического кода с использованием CodeDOM

РЕЗЮМЕ: В этой статье объясняется, как CodeDOM может быть использован для генерации кода динамически и построить его с помощью динамического компиляция кода. Это также объясняет, как применять пользовательские атрибуты.

0 голосов
/ 16 октября 2016

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

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