F# 将匿名类型转换为结构记录
F# casting anonymous type to struct record
我从 c# 数据库服务中收集了简单的匿名对象(我可以查看它但不能修改代码),看起来像:
entities[InfoKey].Add(
new
{
id = (int)result[0],
mpvId = Convert.ToUInt32(result[1]),
date = ((DateTime)result[2]).ToString("yyyy-MM-dd HH:mm:ss"),
systemId = Convert.ToUInt32(result[3]),
name = (string)result[4]
});
现在在 f# 服务中,我可以实际做一些事情,我希望将其转换为记录(这样我就可以对其进行一些实际操作),所以我创建了类似的东西:
type private StatisticsInfoCursor = {
Id: int;
MpvId : uint32;
Date : string;
SystemId : uint32;
Name : string;
}
而且铸造操作看起来,还是应该很简单的:
let infoCursor =
try
rawData.[StatisticsInfoRepository.InfoKey]
|> Seq.map
(fun v ->
let unboxObject = v |> unbox // THIS COUSES EXCEPTION
{Id = unboxObject.Id; MpvCabinetId = unboxObject.MpvCabinetId; Date = unboxObject.Date; SystemId = unboxObject.SystemId; Name = unboxObject.Name})
with
ex -> raise ex
还有一个简单的调用:
for data in infoCursor do
printf "%i - %A" data.Id data.Date
()
但我得到的只是
Unable to cast object of type '<>f__AnonymousType19`5[System.Int32,System.UInt32,System.String,System.UInt32,System.String]' to type 'StatisticsInfoCursor'.
我做错了什么?
编辑:
我用反射做了这样的事情:
let GetPropertyValue (object : obj) propertyName =
let objectType = object.GetType()
let propertyInfo = objectType.GetProperty propertyName
propertyInfo.GetValue object
(GetPropertyValue unboxObject "id") |> unbox;
它有效,但不是太过分了,尤其是当可能有大量数据时??
我认为没有办法做到这一点。假设您有这样的 C# 代码:
public class A {
public static List<object> GetThings() {
var a = new List<object>();
a.Add(new { foo=1, bar="hi" });
return a;
}
}
如评论中所述,.NET 使用名义类型,因此即使您从未命名类型,C# 编译器也会为其生成一些名称。在这种情况下,列表中实际对象的类型将是一些具有丑陋名称的私有类型。您可以使用 ildasm
等反编译工具找出这是什么,在我的例子中,它类似于 <>f__AnonymousType0`2
.
事实证明,您甚至可以尝试在 F# 中使用它:
A.GetThings() |> Seq.map (fun a ->
let it = unbox<``<>f__AnonymousType0`2``<int, string>> a
it )
IDE 知道这个类型,它甚至会告诉你它的成员是什么,但不幸的是(或者幸运的是......),这个类型被标记为 private
所以这给出你一个错误:
error FS1092: The type '<>f__AnonymousType0' is not accessible from this code location
我从 c# 数据库服务中收集了简单的匿名对象(我可以查看它但不能修改代码),看起来像:
entities[InfoKey].Add(
new
{
id = (int)result[0],
mpvId = Convert.ToUInt32(result[1]),
date = ((DateTime)result[2]).ToString("yyyy-MM-dd HH:mm:ss"),
systemId = Convert.ToUInt32(result[3]),
name = (string)result[4]
});
现在在 f# 服务中,我可以实际做一些事情,我希望将其转换为记录(这样我就可以对其进行一些实际操作),所以我创建了类似的东西:
type private StatisticsInfoCursor = {
Id: int;
MpvId : uint32;
Date : string;
SystemId : uint32;
Name : string;
}
而且铸造操作看起来,还是应该很简单的:
let infoCursor =
try
rawData.[StatisticsInfoRepository.InfoKey]
|> Seq.map
(fun v ->
let unboxObject = v |> unbox // THIS COUSES EXCEPTION
{Id = unboxObject.Id; MpvCabinetId = unboxObject.MpvCabinetId; Date = unboxObject.Date; SystemId = unboxObject.SystemId; Name = unboxObject.Name})
with
ex -> raise ex
还有一个简单的调用:
for data in infoCursor do
printf "%i - %A" data.Id data.Date
()
但我得到的只是
Unable to cast object of type '<>f__AnonymousType19`5[System.Int32,System.UInt32,System.String,System.UInt32,System.String]' to type 'StatisticsInfoCursor'.
我做错了什么?
编辑:
我用反射做了这样的事情:
let GetPropertyValue (object : obj) propertyName =
let objectType = object.GetType()
let propertyInfo = objectType.GetProperty propertyName
propertyInfo.GetValue object
(GetPropertyValue unboxObject "id") |> unbox;
它有效,但不是太过分了,尤其是当可能有大量数据时??
我认为没有办法做到这一点。假设您有这样的 C# 代码:
public class A {
public static List<object> GetThings() {
var a = new List<object>();
a.Add(new { foo=1, bar="hi" });
return a;
}
}
如评论中所述,.NET 使用名义类型,因此即使您从未命名类型,C# 编译器也会为其生成一些名称。在这种情况下,列表中实际对象的类型将是一些具有丑陋名称的私有类型。您可以使用 ildasm
等反编译工具找出这是什么,在我的例子中,它类似于 <>f__AnonymousType0`2
.
事实证明,您甚至可以尝试在 F# 中使用它:
A.GetThings() |> Seq.map (fun a ->
let it = unbox<``<>f__AnonymousType0`2``<int, string>> a
it )
IDE 知道这个类型,它甚至会告诉你它的成员是什么,但不幸的是(或者幸运的是......),这个类型被标记为 private
所以这给出你一个错误:
error FS1092: The type '<>f__AnonymousType0' is not accessible from this code location