Можно ли объявить анонимный тип в C # с переменным / динамическим набором полей? - PullRequest
10 голосов
/ 16 сентября 2011

В C # я хотел бы выяснить, возможно ли объявить анонимный тип, где поля неизвестны до времени выполнения.

Например, если у меня есть список пар ключ / значение, могу ли я объявить анонимный тип на основе содержимого этого списка? Конкретный случай, с которым я работаю, это передача параметров в Dapper, где я заранее не знаю, сколько у меня будет параметров.

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

Я хотел бы преобразовать этот Список (или эквивалентную Карту) в анонимный тип, который я могу передать в Dapper в качестве параметров запроса. Поэтому в идеале приведенный выше список должен выглядеть примерно так, если его определить как анонимный тип:

new { key1=value1, key2=value2, ... }

Я видел несколько вопросов о StackOverflow, спрашивающих о расширении анонимных типов после того, как они объявлены ("объекты расширения"), или объявлении произвольных полей в объекте после его создания, но мне не нужно чтобы сделать это ... Мне просто нужно объявить типы динамически заранее. Я подозреваю, что это потребует некоторой фантазии, если это вообще возможно.

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

В качестве альтернативы, если кто-то знает о лучшем способе передачи параметров запроса в Dapper (вместо объявления анонимного класса), я также хотел бы услышать об этом.

Спасибо!

UPDATE

Извините за задержку с возвращением к этому! Все эти ответы были великолепны, я хотел бы дать очки всем. В итоге я использовал решение jbtule (с редактором Сэмом Саффроном), передав IDynamicParameters Dapper, поэтому я чувствовал, что должен дать ему ответ. Другие ответы тоже были хорошими и отвечали на конкретные вопросы, которые я задавал. Я действительно ценю время каждого на этом!

Ответы [ 3 ]

12 голосов
/ 16 сентября 2011

Создатели Dapper прекрасно знали об этой проблеме.Такая функциональность действительно необходима для помощников INSERT и UPDATE.

Методы Query, Execute и QueryMultiple принимают параметр dynamic.Это может быть анонимный тип, конкретный тип или объект, который реализует IDynamicParameters.

public interface IDynamicParameters
{
    void AddParameters(IDbCommand command, Identity identity);
}

Этот интерфейс очень удобен, AddParameters вызывается непосредственно перед запуском любого SQL.Это не только дает вам богатый контроль над параметрами, отправляемыми в SQL.Это позволяет вам подключать специфичные для БД DbParameters, так как у вас есть доступ к команде (вы можете привести ее к специфичной для БД).Это позволяет поддерживать параметры табличных значений и так далее.

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
10 голосов
/ 16 сентября 2011

В C # я хотел бы выяснить, возможно ли объявить анонимный тип, где поля неизвестны до времени выполнения.

Анонимные типы генерируются компилятором,Вы хотите знать, будет ли компилятор генерировать вам сгенерированный компилятором тип с типами полей, неизвестными компилятору .Ясно, что он не может этого сделать;как вы правильно догадываетесь, вам не повезло.

Я видел несколько вопросов о StackOverflow, спрашивающих о расширении анонимных типов после того, как они объявлены ("объекты exteo")

Обычно мы называем эти объекты "расширения".

Если вы хотите создать объект расширения на основе словаря пар ключ-значение, то используйте для этого класс ExpandoObject.Подробности смотрите в этой статье MSDN:

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

Если вы хотите создать подлинный класс .NET во время выполнения, вы тоже можете это сделать.Как вы правильно заметили, для этого нужно какое-то причудливое размышление.То, что вы хотите сделать, это сделать коллекционную сборку (так называемую, потому что в отличие от обычной сборки вы генерируете ее во время выполнения, а сборщик мусора очищает ее, когда вы закончите с ней.)

См. http://msdn.microsoft.com/en-us/library/dd554932.aspx для получения подробной информации о том, как сделать коллекционную сборку и создать в ней тип с помощью TypeBuilder.

7 голосов
/ 16 сентября 2011

Вы не можете использовать анонимный тип. Анонимные типы генерируются компилятором, а не во время выполнения. Вы, конечно, могли бы использовать dynamic, хотя:

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

foreach(var item in paramList)
{
    objAsDict.Add(item.Item1, item.Item2);
}

Затем вы можете использовать dynamicObj как обычный объект:

Console.WriteLine(dynamicObj.key1); // would output "value1"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...