0

文字列を C# コードとして扱えるようにするメソッド、注釈、またはその他のものが必要です。

CodeDom、Reflection、および T4 テンプレートについて読みましたが、それは私が探しているものではありません。

私が必要としているのはもっと単純なことです。実行時にコードを生成したくありません。

これが私が望むものを明確にするための例です。VS2010、Entity Framework 5、および Code First アプローチを使用しています。

エンティティ タイプごとに Insert メソッドがあります。Cliente以下は、 (コスチューム)を挿入するメソッドのコードです。Clienteがデータベースに存在する場合、挿入ではなく更新されます。

    public int InsertarCliente(Cliente cliente)
    {
        int id = cliente.ClienteId;

        try
        {
            if (id != -1)
            {
                var clt = db.Clientes.Find(id);
                clt.Nombre = cliente.Nombre;
                clt.Apellido1 = cliente.Apellido1;
                clt.Apellido2 = cliente.Apellido2;
                // more similar statements
            }
            else
                db.Clientes.Add(cliente);

            db.SaveChanges();
            return cliente.ClienteId;
        }
        catch (DbEntityValidationException exc)
        {
            // code
        }
    }

CodeDom を使用して、任意のエンティティ型で機能するジェネリック メソッドを作成しようとしていました。メソッドが機能しない理由はわかっています。CodeDom は任意のコードをコンパイルおよび実行しません。ステートメント、クラス、メソッドなどを使用して、追加の名前空間が必要です。そのメソッドは機能しません。やろうとしていた:

    public int Insertar<TEntity>(TEntity entidad, string[] atributos)
            where TEntity : class
    {
        string nombreEntidad = entidad.GetType().Name;
        string entidadId = nombreEntidad + "Id";
        string tabla = nombreEntidad + "s";

        int id = Convert.ToInt32(
             entidad.GetType().GetProperty(entidadId).GetValue(entidad, null));

        try
        {
            CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("CSharp");
            CompilerParameters cp = new CompilerParameters();
            cp.GenerateExecutable = false;
            cp.GenerateInMemory = true;
            CompilerResults cr;
            string codigo;

            if (id != -1)
            {
                codigo = "var entidadAlmacenada = db." + tabla + ".Find(id);";
                cr = codeProvider.CompileAssemblyFromSource(cp, codigo);
                CompilerResults cr2;
                string codigoActualizador;

                foreach (string atr in atributos)
                {
                    codigoActualizador =
                        "entidadAlmacenada." + atr + " = entidad." + atr + ";";
                    cr2 = codeProvider.CompileAssemblyFromSource(
                              cp, codigoActualizador);
                }                        
            }
            else
            {
                codigo = "db." + tabla + ".Add(entidad);";
                cr = codeProvider.CompileAssemblyFromSource(cp, codigo);
            }

            db.SaveChanges();
            return Convert.ToInt32(
                entidad.GetType().GetProperty(entidadId).GetValue(entidad, null));
        }
        catch (DbEntityValidationException exc)
        {
            // code
        }
    }

コードを表す文字列を、それが表すコードに変換 (インライン) する方法が必要です。

何かのようなもの:

    string code = "line of code";
    code.toCode(); // or
    toCode(code); // or
    [ToCode]
    code;

書きすぎて申し訳ありませんが、今回ははっきりさせておきたいと思います。

私が必要とするのは、「コードを含む」文字列をコンパイル前にコードに置き換えることです。実行時のコンパイルや実行はありません。

そのようなことをする方法はありますか?

ティア

編集:

上記の例はほんの一例です。しかし、どのような状況でも「文字列からコードへの変換」が必要です。

4

5 に答える 5

1

動的コード生成で間違ったツリーを上っているように感じます。

私はちょうど今週末、非常に似たようなことをしました。ODBC から EF にテーブルを転送します。

申し訳ありませんが、この例をよりコンパクトにする時間がありません。それは一般的ですが、あなたが求めていることと非常に似ていると思います:

using Accounting.Domain.Concrete;
using Accounting.Domain.Entities;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Design.PluralizationServices;
using System.Data.Entity.Migrations;
using System.Data.Odbc;
using System.Globalization;
using System.Linq;

namespace QuickBooks.Services
{
    public class QuickBooksSynchService
    {
        string qodbcConnectionString = @"DSN=QuickBooks Data;SERVER=QODBC;OptimizerDBFolder=%UserProfile%\QODBC Driver for QuickBooks\Optimizer;OptimizerAllowDirtyReads=N;SyncFromOtherTables=Y;IAppReadOnly=Y";
        PluralizationService pluralizationService = PluralizationService.CreateService(CultureInfo.CurrentCulture);
        readonly int companyID;

        public QuickBooksSynchService(string companyName)
        {
            // Make sure the name of QODBC company is same as passed in
            using (var con = new OdbcConnection(qodbcConnectionString))
            using (var cmd = new OdbcCommand("select top 1 CompanyName from Company", con))
            {
                con.Open();
                string currentCompany = (string)cmd.ExecuteScalar();
                if (companyName != currentCompany)
                {
                    throw new Exception("Wrong company - expecting " + companyName + ", got " + currentCompany);
                }
            }

            // Get the company ID using the name passed in (row with matching name must exist)
            using (var repo = new AccountingRepository(new AccountingContext(), true))
            {
                this.companyID = repo.CompanyFileByName(companyName).CompanyId;
            }
        }

        public IEnumerable<T> Extract<T>() where T : new()
        {
            using (var con = new OdbcConnection(qodbcConnectionString))
            using (var cmd = new OdbcCommand("select * from " + typeof(T).Name, con))
            {
                con.Open();
                var reader = cmd.ExecuteReader();
                while (reader.Read())
                {
                    var t = new T();

                    // Set half of the primary key
                    typeof(Customer).GetProperty("CompanyId").SetValue(t, this.companyID, null);

                    // Initialize all DateTime fields
                    foreach (var datePI in from p in typeof(Customer).GetProperties()
                                           where p.PropertyType == typeof(DateTime)
                                           select p)
                    {
                        datePI.SetValue(t, new DateTime(1900, 1, 1), null);
                    }

                    // Auto-map the fields
                    foreach (var colName in from c in reader.GetSchemaTable().AsEnumerable()
                                            select c.Field<string>("ColumnName"))
                    {
                        object colValue = reader[colName];
                        if ((colValue != DBNull.Value) && (colValue != null))
                        {
                            typeof(Customer).GetProperty(colName).SetValue(t, colValue, null);
                        }
                    }

                    yield return t;
                }
            }
        }

        public void Load<T>(IEnumerable<T> ts, bool save) where T : class
        {
            using (var context = new AccountingContext())
            {
                var dbSet = context
                                .GetType()
                                .GetProperty(this.pluralizationService.Pluralize(typeof(T).Name))
                                .GetValue(context, null) as DbSet<T>;

                if (dbSet == null)
                    throw new Exception("could not cast to DbSet<T> for T = " + typeof(T).Name);

                foreach (var t in ts)
                {
                    dbSet.AddOrUpdate(t);
                }

                if (save)
                {
                    context.SaveChanges();
                }
            }
        }
    }
}
于 2013-01-29T09:26:09.013 に答える
1

CSScriptを見てみましょう

CS-Script は、ECMA 準拠の C# をプログラミング言語として使用する CLR (共通言語ランタイム) ベースのスクリプト システムです。CS-Script は現在、Mono を完全にサポートする CLR (.NET 2.0/3.0/3.5/4.0/4.5) の Microsoft 実装を対象としています。

PS。あなたの例から判断すると、実行時にコードを生成するのではなく、一般的な DB リポジトリの作成に時間を費やす必要があります。

于 2013-01-29T09:11:39.287 に答える
0

個人的には、IQueryable コレクションを公開する一般的なリポジトリ パターン (Google および asp.net mvc サイトで多くの結果) を実装するだけなので、IQueryable コレクションを直接クエリすることができます。

このチュートリアルのようなもの http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an- asp-net-mvc-アプリケーション

于 2013-01-29T09:14:21.687 に答える
0

Roslyn API をコンパイラに使用できるようにする新しい .net フレームワークの機能を使用してみてください。

Roslyn を使用したこの Read-Eval-Print ループの例から、必要なコード サンプルを正確に取得できます。

http://gissolved.blogspot.ro/2011/12/c-repl.html http://blogs.msdn.com/b/visualstudio/archive/2011/10/19/introducing-the-microsoft-roslyn-ctp .aspx

于 2013-01-29T09:11:33.967 に答える
0

あなたがやろうとしていることを達成するための代替の(そして私的に好ましい)アプローチは、db.Set<TEntity>().Find(id)etcを使用することです

于 2013-01-29T09:17:36.870 に答える