Tạo một lớp động từ các loại được tìm nạp trong thời gian chạy


20

Có thể thực hiện các thao tác sau trong C # (hoặc bằng bất kỳ ngôn ngữ nào khác) không?

  1. Tôi đang tìm nạp dữ liệu từ cơ sở dữ liệu. Trong thời gian chạy, tôi có thể tính toán số lượng cột và kiểu dữ liệu của các cột được tìm nạp.

  2. Tiếp theo tôi muốn "tạo" một lớp với các kiểu dữ liệu này dưới dạng các trường. Tôi cũng muốn lưu trữ tất cả các hồ sơ mà tôi đã tìm nạp trong một bộ sưu tập.

Vấn đề là tôi muốn thực hiện cả bước 12 khi chạy

Điều này có thể không? Tôi hiện đang sử dụng C # nhưng tôi có thể chuyển sang thứ khác nếu tôi cần.


4
Bạn có thực sự cần điều này? Bạn chắc chắn có thể (A) tạo ra một lớp tùy chỉnh như những người khác đã chỉ ra, nhưng bạn cũng cần (B) biết cách sử dụng nó trong thời gian chạy. Phần (B) có vẻ như cũng rất nhiều công việc với tôi. Có gì sai khi giữ dữ liệu bên trong đối tượng Dataset hoặc một số loại bộ sưu tập như từ điển? Bạn đang cố làm gì vậy?
Công việc

Hãy chắc chắn rằng bạn đã xem công việc mà Rob Conery đã thực hiện dynamictrong Massive: blog.wekeroad.com/helpy- ware / and
Robert Harvey

1
Python cho phép khai báo lớp động và trên thực tế, nó phổ biến. Có một hướng dẫn của David Mertz từ khoảng năm 2001 (Tôi đã tìm kiếm nó nhưng không thể tìm thấy liên kết chính xác). Nó là đơn giản.
smci

@RobertHarvey Liên kết bạn chia sẻ đã chết. Bạn có biết tôi có thể tìm thấy nó ở đâu không?
Jože

1
Mặc dù về mặt kỹ thuật có thể, tôi sẽ phải đặt câu hỏi về giá trị của việc đó. Điểm đánh máy mạnh và các lớp là để tại thời điểm biên dịch, bạn có thể sử dụng thông tin lớp để kiểm tra lỗi cú pháp (thế hệ JITers động mới hơn có thể tối ưu hóa mà không cần điều này). Rõ ràng bằng cách cố gắng sử dụng kiểu gõ động trong môi trường được gõ mạnh sẽ có nghĩa là bạn mất tất cả các lợi thế của một trong hai mô hình ...
ArTs

Câu trả lời:


28

Sử dụng CodeDom. Đây là một cái gì đó để bắt đầu

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

Nó tạo ra một hội đồng 'Test.Docate.dll' với lớp này trong đó

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

Bạn cũng có thể sử dụng các tính năng động của C #

Lớp DynamicEntity, không cần tạo bất cứ thứ gì khi chạy

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

Và sử dụng nó như thế này

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;

6

Có, bạn có thể sử dụng phản xạ phát ra để làm điều này. Manning có những gì có vẻ là một cuốn sách tuyệt vời sắp ra mắt về điều này: Metaprogramming in .NET .

BTW: tại sao không sử dụng danh sách chứa từ điển hoặc tương tự để lưu trữ từng bản ghi với tên trường làm khóa?


1
Cảm ơn bạn đã tham khảo lập trình Meta. Đây là một vài thứ khác tôi tìm thấy: vslive.com/Blogs/News-and-Tips/2016/03/iêu
Leo Gurdian 22/03/2017
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.