Хорошие примеры использования динамического ключевого слова .NET 4 с Linq? - PullRequest
18 голосов
/ 07 ноября 2010

Итак, я только что получил рекомендацию от Amazon для LINQ для объектов с использованием C # 4.0: использование и расширение LINQ для объектов и параллельный LINQ (PLINQ) .

В нем говорится, что в книге вводится использование ключевого слова dynamic с Linq, что заставило меня задуматься:

Какую удивительность вы могли бы сделать с ключевым словом dynamic, которое иначе нельзя было бы сделать с Linq?

Ответы [ 3 ]

21 голосов
/ 07 ноября 2010

Вот идея: комбинируя 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.

4 голосов
/ 22 июля 2014

Джо ответ круто.У меня есть идея, как упростить использование.Если вы добавите это в класс расширения:

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.

0 голосов
/ 29 декабря 2014

То, что я сделал, дает мне результат, но я думаю, что есть лучший способ.

 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();      
}
...