[英]How to convert IDictionary<TKey, List<TValue> > to IDictionary<TKey, IEnumerable<TValue> >?
[英]How to convert List<Dapper.SqlMapper.FastExpando> to runtime type (List<IDictionary<string,object>>)
我正在使用具有IEnumerable<dynamic>
的返回符號的方法。 在運行特定調用時,它將返回List<Dapper.SqlMapper.FastExpando>
。
var x0 = repo.Find(proc, param);
//x0 runtime type is {List<Dapper.SqlMapper.FastExpando>}
LINQPad.Extensions.Dump
指示x0
的運行時類型為: List<IDictionary<String, Object>>
但我似乎無法LINQPad.Extensions.Dump
轉換/轉換為List<IDictionary<String, Object>>
。 這是Linqpad轉儲的屏幕截圖:
最終,我需要將每個字典中的所有值連接到單個IEnumerable<DateTime>
。
IEnumerable<DateTime> GetDates(int productId)
{
const string proc = "[dbo].[myproc]";
dynamic param = new { Id = "asdf" };
var x0 = repo.Find(proc, param);
//...
//linq conversion from x0 to IEnumerable<DateTime> here.
}
我收到錯誤
List<IDictionary<String, Object>> x5 = repo.Find(proc, param);
結果是:
RuntimeBinderException: Cannot implicitly convert type 'object' to
'System.Collections.Generic
.List<System.Collections.Generic.IDictionary<string,object>>'.
An explicit conversion exists (are you missing a cast?)
背景:我使用的是Dapper
包裝程序,無法更改返回非規范化結果的數據庫表/存儲過程。 sproc返回100列的1行,而不是100行的1個數據元素。 我想避免創建一個代表100列的類,並想利用Dapper
的自動能力通過columnName,columnValue的IDictionary將列數據轉置為行。
更新這似乎是動態參數的問題。 內聯指定時,它可以工作。 如果在本地指定,然后作為參數傳遞,則失敗。
IEnumerable<DateTime> GetDates(int productId)
{
const string proc = "[dbo].[myproc]";
dynamic param = new { Id = "asdf" };
//next line throws RuntimeBinderException: 'object' does not
//contain a definition for 'First'.
//IDictionary<String, object> x0 = repo.Find(proc, param).First();
//this succeeds:
IDictionary<String, object> x0 = repo.Find(proc, new { Id = "asdf" }).First();
IEnumerable<DateTime> qry2
= x0.Values.AsQueryable()
.Where(x => x != null)
.Select(x => (DateTime) x);
return qry2;
}
這是“ Find
和Query
的簽名:
//Repository::Find
public IEnumerable<dynamic> Find(string procName, object param = null)
//Dapper SqlMapper::Query
public static IEnumerable<dynamic> Query(this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
您可以使用LINQ Cast
方法Cast
轉換序列中的每個項目。
List<IDictionary<String, Object>> data = repo.Find(proc, param)
.AsEnumerable()
.Cast<IDictionary<String, Object>>()
.ToList();
Repo.Find
不返回IEnumerable<dynamic>
。 它返回object
。 如果您確定它將始終返回List<IDictionary<String, Object>>
,請執行以下操作:
List<IDictionary<String, Object>> x5 = (List<IDictionary<String, Object>>)repo.Find(proc, param);
因此,問題在於,通過將param指定為dynamic
會導致方法被動態調用,並且擴展方法無法再被鏈接。
因此,您可以只使用var
而不使用dynamic
:
var param = new { Id = "asdf" };
var data = repo.Find(proc, param)
.Cast<IDictionary<String, Object>>()
.ToList();
或者只是在調用之前將dynamic
參數投射到object
:
var data = repo.Find(proc, (object)param)
.Cast<IDictionary<String, Object>>()
.ToList();
或者,如果Find
確實返回了System.Collections.Generic.List<Dapper.SqlMapper.FastExpando>
的運行時類型,只需將結果System.Collections.Generic.List<Dapper.SqlMapper.FastExpando>
為dynamic
,以確保在分配它之前使用它的運行時類型,將其分配給它很重要IEnumerable<>
特別是因為它是協變量類型( IList<>
或List<>
將失敗)。
IEnumerable<IDictionary<String, Object>> data = (dynamic) repo.Find(proc, param);
不要從您的方法中動態傳遞回去。 Dapper具有ToList <T>擴展方法,因此您可以轉換為任何受支持的類型。 在這種情況下,如果您確實需要低級別的關聯數組,請傳回List <字典<字符串<對象,>>。
同樣值得注意的是,C#dynamic不會跨程序集邊界封送,因此這可能是您遇到的一個問題。 如果要在程序集之間進行封送處理,則需要使用Expando,List <Dictionary <字串,對象>>或兩個程序集都引用的其他類型。
這是Dapper SQLMapper源的舊版本,其中包括FastExpando(第941行)。 注意FastExpando的類定義。
私有類FastExpando:System.Dynamic.DynamicObject,IDictionary <字符串,對象>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.