servicestack,C#,servicestack" /> servicestack,C#,servicestack" />

C# 使用C动态更改类型

C# 使用C动态更改类型,c#,servicestack,C#,servicestack,我对C和ServiceStack非常陌生,我正在从事一个小项目,该项目包括调用第三方API,并通过ServiceStack的ORMLite将从API获取的数据加载到关系数据库中 其思想是让API的每个端点都有一个可重用的模型,该模型确定如何在API的响应中接收它,以及如何将它插入数据库 因此,我有如下几点: [Route("/api/{ApiEndpoint}", "POST")] public class ApiRequest : IReturn<ApiResponse&

我对C和ServiceStack非常陌生,我正在从事一个小项目,该项目包括调用第三方API,并通过ServiceStack的ORMLite将从API获取的数据加载到关系数据库中

其思想是让API的每个端点都有一个可重用的模型,该模型确定如何在API的响应中接收它,以及如何将它插入数据库

因此,我有如下几点:

    [Route("/api/{ApiEndpoint}", "POST")]
    public class ApiRequest : IReturn<ApiResponse>
    {
        public Int32 OrderId { get; set; }
        public DateTime PurchaseDate { get; set; }
        public String ApiEndpoint { get; set; }
    }

    public class ApiResponse
    {
        public Endpoint1[] Data { get; set; }
        public String ErrorCode { get; set; }
        public Int32 ErrorNumber { get; set; }
        public String ErrorDesc { get; set; }
    }

    public class Endpoint1
    {
        [AutoIncrement] 
        public Int32 Id { get; set; }

        [CustomField("DATETIME2(7)")]
        public String PurchaseDate { get; set; }

        [CustomField("NVARCHAR(50)")]
        public String Customer { get; set; }

        [CustomField("NVARCHAR(20)")]
        public String PhoneNumber { get; set; }

        public Int32 Amount { get; set; }
    }
我希望在发出请求时调用getModel,这样我就可以在ApiRequest类中传入ApiEndpoint字段,并存储我希望数据字段具有的类型,这样我就可以在ApiResponse类中动态更改它

此外,还有ORM部分,我在其中迭代每个端点,并使用每个端点的模型/类型创建不同的表。大概是这样的:

public class DataModels
    {
        public Type getModel(String endpoint)
        {
            Dictionary<String, Type> models = new Dictionary<String, Type>();

            models.Add("Endpoint1", typeof(Endpoint1));
            // models.Add("Endpoint2", typeof(Endpoint2));
            // models.Add("Endpoint3", typeof(Endpoint3));
            // and so forth...

            return models[endpoint];  
        }

    }
endpoints.ForEach(
       (endpoint) =>
            {
                db.CreateTableIfNotExists<Endpoint1>();
                // inserting data, doing other work etc
            }
);
但是,我想再次在这里调用getModel,并用它定义我正在迭代的特定端点的模型

我尝试在这两个地方调用getModel,但我总是返回错误,例如无法将变量用作类型,以及其他。。。所以我肯定做错了什么


请随意建议使用不同的方法来创建getModel。这正是我想到的,但我可能忽略了一个更简单的方法。

当我正确理解您时,您有不同的API调用,它们都返回相同的对象。唯一的区别是,字段数据可以有不同的类型

然后,您只需将数据类型更改为对象:

public object Data { get; set; }
然后简单地将其转换为所需的对象:

var data1=(Endpoint1[]) response.Data;

您将很难尝试动态创建.NET类型,这需要高级使用Reflection.Emit。尝试使用ServiceStack动态创建请求DTO是自欺欺人的,因为客户机和元数据服务需要具体的类型才能使用类型化API调用服务

我不能真正理解你的例子,但我最初的方法是你是否可以使用一个单一的服务,也就是说,而不是尝试动态地创建多个服务。与OrmLite类似,如果POCOs的模式相同,听起来您将能够扁平化您的数据模型并使用单个数据库表

AutoQuery是一种从一个具体的请求DTO中提取数据的方法,它实际上是您所需要的最小类型

因此,虽然是这样,但您可以使用继承来重用公共属性,例如:

[Route("/api/{ApiEndpoint}/1", "POST")]
public ApiRequest1 : ApiRequestBase<Endpoint1> {}

[Route("/api/{ApiEndpoint}/2", "POST")]
public ApiRequest2 : ApiRequestBase<Endpoint1> {}

public abstract class ApiRequestBase<T> : IReturn<ApiResponse<T>>
{
    public int OrderId { get; set; }
    public DateTime PurchaseDate { get; set; }
    public string ApiEndpoint { get; set; }
}

挑战在于我想以一种动态的方式来塑造这个类型。因此,我不想手动编写var data1=Endpoint1[],而是类似于var data1=getmodeleendpoint[],其中方法端点中的参数将端点的名称作为字符串包含,并返回该端点的适当类型。这有意义吗?@jgozal:你想要的不是C语言的惯用用法。你还试图违反我们首先使用类型安全的原因:开发人员想要编译时错误,而不是运行时错误。还有许多其他方法可以解决这个问题,例如,泛型不涉及试图绕过类型安全规则。@jgozal似乎有点做作请可怜我。我来自一个JavaScript背景,在那里一切都是可能的,所以我试图理解如何在不太冗长的同时用C做事情。那你建议我怎么做?我应该只写15个不同数据类型的ApiResponse类吗?@jgozal:不要写15个复制/粘贴类。请看一看C泛型。我会给你谷歌链接,但由于某种原因谷歌今天在工作中被阻止:-/谢谢你的回复。我需要花几分钟的时间来消化它,但我要说的是,我的表没有相同的模式,因此我尝试动态更改db.CreateTableIfNotExists;中的类型;。表名不是很重要,而是我使用它创建的列type@jgozal如果它们没有相同的模式,那么您应该创建不同的数据模型来捕获模式?我没有看到使用Reflection.Emit在运行时动态创建类型的好处,因为C有一个非常好的DSL来描述具有自动属性的类型。哦,我正在创建不同的数据模型。Endpoint1就是其中之一。但我仍在试图弄清楚,当我创建表时,以及当我调用第三方API(如果这样做的话)时,如何在它们之间切换sense@jgozal:阅读这里的字里行间;我认为,您在Javascript方面的经验导致您在运行时更改给定变量的类型时非常冒失。而Javascript允许这样的事情;从可读性和降低复杂性的角度来看,这从来都不是一个好主意。C特别试图通过强制类型安全性来防止这种情况发生。而不是试图找到一种方法绕过C的类型安全;我建议你改为学习如何使用它,因为它将是戏剧性的
无论这是不是一个好主意,这都是我们在生产代码中一直在做的事情,当使用JS在运行时动态地改变事情时。我不知道这为什么这么危险。你只是在做决定,就像你会做一个简单的条件,例如,如果端点是x,返回x的类型。我并不是想在C语言中推广这种方法,我从评论中了解到,它不是如何实现的。但无论如何,我不明白为什么这种方法是危险的。
public class ApiResponse<T>
{
    public T[] Data { get; set; }
    public String ErrorCode { get; set; }
    public Int32 ErrorNumber { get; set; }
    public String ErrorDesc { get; set; }
}
const string tableName = "Entity1";
using (var db = OpenDbConnection())
{
    db.DropAndCreateTable<GenericEntity>(tableName);

    db.Insert(tableName, new GenericEntity { Id = 1, ColumnA = "A" });

    var rows = db.Select(tableName, db.From<GenericEntity>()
        .Where(x => x.ColumnA == "A"));

    Assert.That(rows.Count, Is.EqualTo(1));

    db.Update(tableName, new GenericEntity { ColumnA = "B" },
        where: q => q.ColumnA == "A");

    rows = db.Select(tableName, db.From<GenericEntity>()
        .Where(x => x.ColumnA == "B"));

    Assert.That(rows.Count, Is.EqualTo(1));
}
public static class GenericTableExtensions
{
    static object ExecWithAlias<T>(string table, Func<object> fn)
    {
        var modelDef = typeof(T).GetModelMetadata();
        lock (modelDef)
        {
            var hold = modelDef.Alias;
            try
            {
                modelDef.Alias = table;
                return fn();
            }
            finally
            {
                modelDef.Alias = hold;
            }
        }
    }

    public static void DropAndCreateTable<T>(this IDbConnection db, string table)
    {
        ExecWithAlias<T>(table, () => { 
            db.DropAndCreateTable<T>();
            return null;
        });
    }

    public static long Insert<T>(this IDbConnection db, string table, T obj, bool selectIdentity = false)
    {
        return (long)ExecWithAlias<T>(table, () => db.Insert(obj, selectIdentity));
    }

    public static List<T> Select<T>(this IDbConnection db, string table, SqlExpression<T> expression)
    {
        return (List<T>)ExecWithAlias<T>(table, () => db.Select(expression));
    }

    public static int Update<T>(this IDbConnection db, string table, T item, Expression<Func<T, bool>> where)
    {
        return (int)ExecWithAlias<T>(table, () => db.Update(item, where));
    }
}
public class Table1 : TableBase {}
public class Table2 : TableBase {}
public class Table3 : TableBase {}