Обработать строку как код в C #

Я хочу метод, аннотацию или что-то еще, что позволяет мне рассматривать строку как код C #.

Я читал о шаблонах CodeDom, Reflection и T4, но это не то, что я ищу.

Надеюсь, мне будет проще. Мне не нужен код, созданный во время выполнения.

Вот пример, чтобы прояснить, что я хочу. Я использую VS2010, Entity Framework 5 и подход Code First.

У меня есть метод Insert для каждого типа сущности. Ниже приведен код для метода для вставки Cliente (Costumer). Если в базе данных существует 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 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;

Извините, если я пишу слишком много, но на этот раз хочу быть ясным.

Мне нужно, чтобы строка «содержащий код» заменялась кодом до времени компиляции. Нет компиляции или выполнения во время выполнения.

Есть ли способ сделать что-то подобное?

ТИА

РЕДАКТИРОВАТЬ:

Приведенный выше пример был просто примером. Но я хочу, чтобы «строка преобразовывалась в код» в любой ситуации.

0
nl ja de
Вы не можете создать код во время компиляции, а не во время выполнения, правильно? Тогда способ сделать это - использовать шаблоны компиляции кода. Это означает, на практике, либо T4, либо CodeSmith.
добавлено автор Roy Dictus, источник
Если вы знаете, что код будет во время компиляции, просто напишите код.
добавлено автор Jodrell, источник
Можете ли вы на самом деле добиться этого через директивы препроцессора #if ? Если вам нужно обработать string как код, который всегда будет отображаться во время выполнения, а не время компиляции.
добавлено автор Alvin Wong, источник
@MattDavey макросы препроцессора не поддерживаются в C# . Однако вы можете использовать #if .
добавлено автор Alvin Wong, источник
@MattDavey Это действительно отличный способ развлечь других разработчиков.
добавлено автор Alvin Wong, источник
@MattDavey, не так ли? Вы пишете #define blah (x) Console.WriteLine (x) , и никто другой не может скомпилировать код, используя только компилятор C #.
добавлено автор Alvin Wong, источник
@AlvinWong легко интегрировать препроцессор C в процесс сборки. Это всего лишь командная строка exe, ее можно добавить как шаг предварительной сборки. MSBuild делает это довольно плавным.
добавлено автор MattDavey, источник
@Jodrell "Если вы знаете, какой код будет во время компиляции, просто напишите код. - все на борту поезда истины!
добавлено автор MattDavey, источник
@AlvinWong, что вы имеете в виду?
добавлено автор MattDavey, источник
@AlvinWong вам нечего останавливать, используя препроцессор C (не C #) в файлах исходного кода C #. Из Википедии> "Препроцессор C - это отдельная программа, вызываемая компилятором в качестве первой части перевода. Язык директив препроцессора не зависит от грамматики C, поэтому препроцессор C также может использоваться независимо для обработки других типы текстовых файлов. "
добавлено автор MattDavey, источник
Если я правильно понимаю вас, это похоже на то, что вы ищете макросы стиля C на C #? В этом случае вы можете легко использовать препроцессор C в исходных файлах C# ...
добавлено автор MattDavey, источник
@all Я читаю обо всех предложениях. Позвольте мне несколько минут ответить.
добавлено автор user1537004, источник
@AlvinWong Я думаю, что препроцессорные директивы #if сделают работу. :)
добавлено автор user1537004, источник
Теперь я прочитаю ответы на голосование. Извините, я читал по-английски медленно.
добавлено автор user1537004, источник
В вопросе есть редактирование: приведенный выше пример был всего лишь примером. Но я хочу, чтобы «строка преобразовывалась в код» в любой ситуации.
добавлено автор user1537004, источник
Я думаю, что предложение Элвина - это то, что мне нужно. Это не совсем «преобразование строки в код», но может выполнять работу с несколькими операторами. Благодарю.
добавлено автор user1537004, источник

5 ответы

У меня такое чувство, что вы идете по неправильному дереву с генерацией динамического кода.

В этот уик-энд я сделал что-то очень похожее. Он переносит таблицы из 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 Extract() 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("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(IEnumerable 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;

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

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

                if (save)
                {
                    context.SaveChanges();
                }
            }
        }
    }
}
1
добавлено
+1 для «У меня такое чувство, что вы идете по неправильному дереву с генерацией динамического кода». . Особенно для чего-то такого тривиального, как репозиторий.
добавлено автор MattDavey, источник
@MattDavey Я буду читать о репозитории. Я изучаю.
добавлено автор user1537004, источник

Take a look at CSScript

CS-Script - это система сценариев на основе CLR (Common Language Runtime)   который использует ECMA-совместимый C# в качестве языка программирования. CS-Script   в настоящее время нацелен на реализацию Microsoft CLR (.NET   2.0/3.0/3.5/4.0/4.5) с полной поддержкой Mono.

PS. Судя по вашему примеру, вы, вероятно, должны потратить свое время на создание родового хранилища баз данных вместо генерации кода во время выполнения.

1
добавлено
OP говорит: Мне нужно, чтобы строка «содержащий код» была заменена этим кодом до времени компиляции. Нет компиляции или выполнения во время выполнения.
добавлено автор Alvin Wong, источник

Попробуйте использовать возможности новой инфраструктуры .net, которые позволяют использовать API Roslyn для компилятора.

Вы можете получить именно тот пример кода, который вам нужен, из этого примера цикла Read-Eval-Print Loop, используя Roslyn:

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

0
добавлено

лично я бы просто реализовал общий шаблон репозитория (много результатов в Google и сайте asp.net mvc), который предоставляет коллекцию IQueryable, поэтому вы можете просто запросить коллекцию IQueryable напрямую

something like this tutorial 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-application

0
добавлено

An alternative (and imho preferrable) approach to achieve what you are trying to do is using db.Set().Find(id) etc

0
добавлено
В вашем ответе не говорится о преобразовании «строка в код», но я считаю это полезным. Благодарю.
добавлено автор user1537004, источник
Microsoft Stack Jobs
Microsoft Stack Jobs
1 788 участник(ов)

Work & freelance only Microsoft Stack. Feed https://t.me/Microsoftstackjobsfeed Чат про F#: @Fsharp_chat Чат про C#: @CSharpChat Чат про Xamarin: @xamarin_russia Чат общения:@dotnettalks

Microsoft Developer Community Chat
Microsoft Developer Community Chat
584 участник(ов)

Чат для разработчиков и системных администраторов Microsoft Developer Community. __________ Новостной канал: @msdevru __________ Баним за: оскорбления, мат, рекламу, флуд, флейм, спам, NSFW контент, а также большое количество оффтоп тем. @banofbot