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


20

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 ben çalışma zamanında hem adım 1 ve 2 yapmak istiyorum

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


4
Buna gerçekten ihtiyacınız var mı? Kesinlikle (A) diğerlerinin işaret ettiği gibi özel bir sınıf oluşturabilirsiniz, ancak (B) çalışma zamanında nasıl kullanılacağını da bilmeniz gerekir. (B) kısmı benim için çok fazla iş gibi görünüyor. Verileri DataSet nesnesinin veya sözlük gibi bir koleksiyonun içinde tutmanın nesi yanlış? Ne yapmaya çalışıyorsun?
Meslek

Rob Conery'nin Massive'da yaptığı işe bir göz attığınızdan emin olun dynamic: blog.wekeroad.com/helpy-stuff/and-i-shall-call-it-massive
Robert Harvey

1
Python dinamik sınıf bildirisine izin verir ve aslında yaygındır. David Mertz tarafından 2001 civarında bir eğitim vardı (onu aradım ama tam bağlantıyı bulamadım). Çok basit.
smci

@RobertHarvey Paylaştığınız bağlantı öldü. Nerede bulabilirim biliyor musun?
Joze

1
Teknik olarak mümkün olmasına rağmen, bunu yapmanın değerini sorgulamak zorunda kalacağım. Güçlü yazım ve sınıfların amacı, derleme zamanında sözdizimi hatalarını kontrol etmek için sınıf bilgisinden faydalanabilmenizdir (daha yeni nesil dinamik JITers bu olmadan optimize edebilir). Açıkça güçlü bir şekilde yazılan bir ortamda dinamik yazmayı kullanmaya çalışmak, her iki paradigmanın tüm avantajlarını kaybettiğiniz anlamına gelir ...
ArTs

Yanıtlar:


28

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' derlemesi 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;

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.