从运行时获取的类型动态生成类


20

是否可以用C#(或任何其他语言)执行以下操作?

  1. 我正在从数据库中获取数据。在运行时,我可以计算获取的列数和数据类型。

  2. 接下来,我想使用这些数据类型作为字段“生成”一个类。我还想存储我在集合中获取的所有记录。

问题是我想在运行时同时执行步骤12

这可能吗?我目前正在使用C#,但如果需要的话,可以改用其他软件。


4
你真的需要这个吗?您可以肯定(A)像其他人指出的那样生成自定义类,但是您还需要(B)知道如何在运行时使用它。(B)部分对我来说似乎也是很多工作。将数据保留在DataSet对象或某种集合(例如字典)中怎么办?你想做什么?
工作

确保您了解Rob Conery dynamic在Massive中所做的工作:blog.wekeroad.com/helpy-stuff/and-i-shall-call-it-massive
罗伯特·哈维

1
Python允许动态类声明,实际上这是很常见的。David Mertz在2001年左右编写了一个教程(我进行了搜索,但找不到确切的链接)。这很简单。
smci 2011年

@RobertHarvey您共享的链接已死。你知道我在哪里可以找到它吗?
Joze 2015年

1
尽管在技术上可行,但我不得不质疑这样做的价值。强类型化和类的要点是,以便在编译时可以使用类信息来检查语法错误(新一代动态JITer可以在不这样做的情况下进行优化)。显然,尝试在强类型环境中使用动态类型将意味着您将失去这两种范例的所有优势...
ArTs 2016年

Answers:


28

使用CodeDom。这是一些入门

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.CodeDom;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            string className = "BlogPost";

            var props = new Dictionary<string, Type>() {
                { "Title", typeof(string) },
                { "Text", typeof(string) },
                { "Tags", typeof(string[]) }
            };

            createType(className, props);
        }

        static void createType(string name, IDictionary<string, Type> props)
        {
            var csc = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v4.0" } });
            var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll"}, "Test.Dynamic.dll", false);
            parameters.GenerateExecutable = false;

            var compileUnit = new CodeCompileUnit();
            var ns = new CodeNamespace("Test.Dynamic");
            compileUnit.Namespaces.Add(ns);
            ns.Imports.Add(new CodeNamespaceImport("System"));

            var classType = new CodeTypeDeclaration(name);
            classType.Attributes = MemberAttributes.Public;
            ns.Types.Add(classType);

            foreach (var prop in props)
            {
                var fieldName = "_" + prop.Key;
                var field = new CodeMemberField(prop.Value, fieldName);
                classType.Members.Add(field);

                var property = new CodeMemberProperty();
                property.Attributes = MemberAttributes.Public | MemberAttributes.Final;
                property.Type = new CodeTypeReference(prop.Value);
                property.Name = prop.Key;
                property.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName)));
                property.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName), new CodePropertySetValueReferenceExpression()));
                classType.Members.Add(property);
            }

            var results = csc.CompileAssemblyFromDom(parameters,compileUnit);
            results.Errors.Cast<CompilerError>().ToList().ForEach(error => Console.WriteLine(error.ErrorText));
        }
    }
}

它使用其中的此类创建程序集“ Test.Dynamic.dll”

namespace Test.Dynamic
{
    public class BlogPost
    {
        private string _Title;
        private string _Text;
        private string[] _Tags;

        public string Title
        {
            get
            {
                return this._Title;
            }
            set
            {
                this._Title = value;
            }
        }
        public string Text
        {
            get
            {
                return this._Text;
            }
            set
            {
                this._Text = value;
            }
        }
        public string[] Tags
        {
            get
            {
                return this._Tags;
            }
            set
            {
                this._Tags = value;
            }
        }
    }
}

您还可以使用C#的动态功能

DynamicEntity类,无需在运行时创建任何内容

public class DynamicEntity : DynamicObject
{
    private IDictionary<string, object> _values;

    public DynamicEntity(IDictionary<string, object> values)
    {
        _values = values;
    }
    public override IEnumerable<string> GetDynamicMemberNames()
    {
        return _values.Keys;
    }
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (_values.ContainsKey(binder.Name))
        {
            result = _values[binder.Name];
            return true;
        }
        result = null;
        return false;
    }
}

像这样使用

var values = new Dictionary<string, object>();
values.Add("Title", "Hello World!");
values.Add("Text", "My first post");
values.Add("Tags", new[] { "hello", "world" });

var post = new DynamicEntity(values);

dynamic dynPost = post;
var text = dynPost.Text;

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.