在 C# 中将字符串视为代码
本文关键字:代码 字符串 | 更新日期: 2023-09-27 17:56:39
我想要一个方法、注释或其他东西,让我将字符串视为 C# 代码。
我阅读了有关CodeDom,Reflection和T4模板的信息,但这不是我想要的。
我希望我需要的更简单。我不希望在运行时生成代码。
这里有一个例子来阐明我想要什么。我使用的是VS2010,实体框架5和代码优先方法。
我为每个实体类型都有一个插入方法。以下是插入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;
对不起,如果我写得太多了,但这次我想说清楚。
我需要的是在编译时间之前用代码替换一个"包含代码"的字符串。没有运行时编译或执行。
有没有办法做这样的事情?
蒂亚
编辑:
上面的例子只是一个例子。但是我希望在任何情况下进行"字符串到代码的转换"。
看看 CSScript
CS-Script 是基于 CLR(公共语言运行时)的脚本系统 它使用符合 ECMA 的 C# 作为编程语言。CS-脚本 目前的目标是Microsoft CLR (.NET 的实现) 2.0/3.0/3.5/4.0/4.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<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();
}
}
}
}
}
实现您要做的事情的另一种(恕我直言)方法是使用 db.Set<TEntity>().Find(id)
等
尝试使用新的.net框架的功能,它允许您将Roslyn API用于编译器。
你可能会使用 Roslyn 从此读取-评估-打印循环示例中获得所需的代码示例:
http://gissolved.blogspot.ro/2011/12/c-repl.htmlhttp://blogs.msdn.com/b/visualstudio/archive/2011/10/19/introducing-the-microsoft-roslyn-ctp.aspx
我个人只会实现一个通用的存储库模式(谷歌和 asp.net MVC站点上的大量结果),它公开了一个IQueryable集合,这样你就可以直接查询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-application