Хорошие примеры использования динамического ключевого слова.NET 4 с Linq?
Поэтому я только что получил рекомендацию Amazon по LINQ для объектов с использованием C# 4.0: использование и расширение LINQ для объектов и параллельного LINQ (PLINQ).
Это говорит о том, что книга вводит использование dynamic
ключевое слово с Linq, которое заставило меня задуматься:
Какую удивительность вы могли бы сделать с dynamic
Ключевое слово, которое вы не могли бы сделать с Linq иначе?
3 ответа
Вот идея: комбинируя LINQ с динамическим, вы можете запрашивать нетипизированные наборы данных, как если бы они были напечатаны.
Например, предположим, что myDataSet является нетипизированным DataSet. С динамической типизацией и методом расширения AsDynamic() возможно следующее:
var query = from cust in myDataSet.Tables[0].AsDynamic()
where cust.LastName.StartsWith ("A")
orderby cust.LastName, cust.FirstName
select new { cust.ID, cust.LastName, cust.FirstName, cust.BirthDate };
Вот как определить метод расширения AsDynamic. Обратите внимание, как он возвращает IEnumerable of dynamic, что делает его подходящим для запросов LINQ:
public static class Extensions
{
public static IEnumerable<dynamic> AsDynamic (this DataTable dt)
{
foreach (DataRow row in dt.Rows) yield return row.AsDynamic();
}
public static dynamic AsDynamic (this DataRow row)
{
return new DynamicDataRow (row);
}
class DynamicDataRow : DynamicObject
{
DataRow _row;
public DynamicDataRow (DataRow row) { _row = row; }
public override bool TryGetMember (GetMemberBinder binder, out object result)
{
result = _row[binder.Name];
return true;
}
public override bool TrySetMember (SetMemberBinder binder, object value)
{
_row[binder.Name] = value;
return true;
}
public override IEnumerable<string> GetDynamicMemberNames()
{
return _row.Table.Columns.Cast<DataColumn>().Select (dc => dc.ColumnName);
}
}
}
Подклассификация DynamicObject позволяет использовать преимущества пользовательского связывания, когда вы сами решаете процесс разрешения имен членов. В этом случае мы привязываем права доступа get и set к извлечению или хранению объектов в базовом DataRow.
Джо ответ круто. У меня есть идея, как упростить использование. Если вы добавите это в класс расширения:
public static class Extensions
{
public static IEnumerable<dynamic> ExecuteSql(this UserQuery uq, string sql)
{
var connStr="Provider=SQLOLEDB.1;"+uq.Connection.ConnectionString;
OleDbConnection connection = new OleDbConnection(connStr);
DataSet myDataSet = new DataSet();
connection.Open();
OleDbDataAdapter DBAdapter = new OleDbDataAdapter();
DBAdapter.SelectCommand = new OleDbCommand(sql, connection);
DBAdapter.Fill(myDataSet);
var result = myDataSet.Tables[0].AsDynamic();
return result;
}
}
Это позволяет использовать такие запросы в LINQPad:
void Main()
{
var query1 = from cust in this.ExecuteSql("SELECT * from Customers")
where cust.ContactName.StartsWith ("C")
orderby cust.ContactName
select new { cust.CustomerID, cust.ContactName, cust.City };
query1.Dump();
}
NB: Вам необходимо добавить следующие ссылки:
- добавлять
System.Data.OleDb
отSystem.Data
сборка в свойствах запроса добавлять
System.Dynamic
к свойствам запросаuq.Connection
доступно только в том случае, если вы связали базу данных с помощью раскрывающегося списка Соединение. Если вы выбрали"<none>"
, произойдет ошибка компиляции.
Обновление: я заметил, что Джо добавил функцию ExecuteQueryDynamic
в последней бета-версии LinqPad v4.53.03, которая может быть использована для этого, например:
void Main()
{
var q=this.ExecuteQueryDynamic("select * from Customers");
q.Dump();
}
Это вернет Customers
таблица из базы данных Northwind как IEnumerable<dynamic>
, используя соединение Linq2Sql.
То, что я сделал, дает мне результат, но я думаю, что есть лучший способ.
using (SqlConnection connection = new SqlConnection(this.Connection.ConnectionString))
{
connection.Open();
SqlCommand command = new SqlCommand(query, connection);
SqlDataReader reader = command.ExecuteReader();
reader.Cast<IDataRecord>().AsQueryable().Dump();
}