it-swarm.asia

Çalışma zamanında getirilen türlerden dinamik olarak sınıf oluşturma

C # 'da (veya başka bir dilde) aşağıdakileri yapmak mümkün mü?

  1. Veritabanından veri alıyorum. Çalışma zamanında getirilen sütunların sayısını ve veri türlerini hesaplayabilirim.

  2. Sonra alan olarak bu veri türleriyle bir sınıf "oluşturmak" istiyorum. Bir koleksiyonda getirdiğim tüm kayıtları da saklamak istiyorum.

Sorun şu ki, her iki adımda da 1 ve 2

Mümkün mü? Şu anda C # kullanıyorum ama gerekirse başka bir şeye geçebilir.

20
Chani

CodeDom kullanın. İşte başlamak için bir şey

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

İçinde bu sınıf ile bir 'Test.Dynamic.dll' derleme oluşturur

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 # 'ın dinamik özelliklerini de kullanabilirsiniz

DynamicEntity sınıfı, çalışma zamanında herhangi bir şey oluşturmanıza gerek yok

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;
    }
}

Ve böyle kullan

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;
28
Mike Koder

Evet, bunu yapmak için yansıma yayar kullanabilirsiniz. Manning bu mükemmel bir kitap gibi görünüyor ne var var: Meta Metagramlama .

BTW: Neden sadece her kaydı alan adları ile birlikte anahtar olarak saklamak için sözlükler veya benzeri bir liste kullanmıyorsunuz?

6
FinnNk