是否可以使用变量/动态字段集在C#中声明匿名类型?

Ega*_*ahn 10 c# dynamic anonymous-types dapper

在C#中,我想弄清楚是否可以声明一个匿名类型,其中字段在运行时才知道.

例如,如果我有一个键/值对列表,我可以根据该列表的内容声明一个匿名类型吗?我正在使用的具体情况是将参数传递给Dapper,我不知道我将提供多少参数.

List<Tuple<string, string>> paramList = new List<Tuple<string, string>>() {
    new Tuple<string, string>("key1", "value1"),
    new Tuple<string, string>("key2", "value2")
    ...
};
Run Code Online (Sandbox Code Playgroud)

我想将此List(或等效的Map)转换为匿名类型,我可以将其作为查询参数传递给Dapper.理想情况下,如果将以上列表定义为匿名类型,则上面的列表最终会如下所示:

new { key1=value1, key2=value2, ... }
Run Code Online (Sandbox Code Playgroud)

我在StackOverflow上看到了几个问题,询问在声明它们之后扩展匿名类型("extendo objects"),或者在创建对象后声明任意字段,但我不需要这样做......我只是需要一次性地动态声明类型.我怀疑它是否需要一些花哨的反思,如果可能的话.

我的理解是编译器在编译时为引擎定义了一个匿名类的类型,所以如果该类的字段在运行时才可用,我可能会运气不好.事实上,我的用例实际上与使用"extendo对象"定义任意字段无关.

或者,如果有人知道更好的方法将查询参数传递给Dapper(而不是声明一个匿名类),我也很想知道这一点.

谢谢!

UPDATE

抱歉延迟回到这个!这些答案都很棒,我希望我能给大家一点.我最终使用了jbtule的解决方案(由Sam Saffron编辑),将IDynamicParameters传递给Dapper,所以我觉得我必须给他答案.其他答案也很好,并回答了我提出的具体问题.我非常感谢大家的时间!

jbt*_*ule 12

Dapper的创作者非常清楚这个问题.真正需要这种功能INSERTUPDATE帮助.

Query,ExecuteQueryMultiple方法都在一个dynamic参数.这可以是匿名类型,具体类型或实现的对象IDynamicParameters.

public interface IDynamicParameters
{
    void AddParameters(IDbCommand command, Identity identity);
}
Run Code Online (Sandbox Code Playgroud)

这个界面非常方便,AddParameters在运行任何SQL之前调用.这不仅可以丰富地控制发送到SQL的参数.它允许您连接DB特定的DbParameters,因为您可以访问该命令(您可以将其强制转换为特定于db的命令).这允许支持表值参数等.

Dapper包含此接口的实现,可用于您的目的DynamicParameters.这允许您连接匿名参数包并添加特定值.

您可以使用AddDynamicParams方法追加匿名类型.

var p = new DynamicParameters();
p.AddDynamicParams(new{a = "1"});
p.AddDynamicParams(new{b = "2", c = "3"});
p.Add("d", "4")
var r = cnn.Query("select @a a, @b b, @c c, @d d", p);
// r.a == 1, r.b == 2, r.c == 3, r.d == 4
Run Code Online (Sandbox Code Playgroud)


Eri*_*ert 10

在C#中,我想弄清楚是否可以声明一个匿名类型,其中字段在运行时才知道.

匿名类型由编译器生成.您想知道编译器是否会生成编译器生成的类型,其中包含编译器不知道的字段类型.显然它不能这样做; 正如你猜测的那样,你运​​气不好.

我已经在StackOverflow上看到几个问题,询问在声明它们之后扩展匿名类型("extendo objects")

我们通常称这些"expando"对象.

如果你想要做的是基于键值对的字典创建一个expando对象,那么使用ExpandoObject类来做到这一点.有关详细信息,请参阅此MSDN文章:

http://msdn.microsoft.com/en-us/magazine/ff796227.aspx

如果你想要做的是在运行时生成一个真正的.NET类,你也可以这样做.正如您所正确指出的那样,您需要一些花哨的反思才能这样做.你想要做的是制作一个可收集的程序集(所谓的,因为与普通程序集不同,你在运行时生成它,垃圾收集器会在你完成它时清理它.)

有关如何使用TypeBuilder创建可收集程序集并向其中发出类型的详细信息,请参阅http://msdn.microsoft.com/en-us/library/dd554932.aspx.

  • Expandos和dapper的问题在于它们没有内部特殊处理,所以params不会从底层IDictionary中提取出来.这就是为什么在这种情况下你可能想要使用`IDynamicParameters` @Egahn ...你可以使用reflection.emit融合2个anon类型中的新类型,但在这种情况下你不需要. (2认同)

Jus*_*ner 7

您不能使用匿名类型.匿名类型由编译器生成,而不是在运行时生成.你当然可以使用dynamic:

dynamic dynamicObj = new ExpandoObject();    
var objAsDict = (IDictionary<String, Object>)dynamicObj;

foreach(var item in paramList)
{
    objAsDict.Add(item.Item1, item.Item2);
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以将dynamicObj用作常规对象:

Console.WriteLine(dynamicObj.key1); // would output "value1"
Run Code Online (Sandbox Code Playgroud)