使用F#中的System.Reflection分配属性值

时间:2014-05-27 20:13:40

标签: f#

我在C#中有以下几行代码:

internal static object AssignMatchingPropertyValues(object sourceObject, object targetObject)
{
    Type sourceType = sourceObject.GetType();
    PropertyInfo[] sourcePropertyInfos = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
    foreach (var sourcePropertyInfo in sourcePropertyInfos)
    {
        var targetPropertyInfo = targetObject.GetType().GetProperty(sourcePropertyInfo.Name);
        if (targetPropertyInfo != null)
        {
            targetPropertyInfo.SetValue(targetObject, sourcePropertyInfo.GetValue(sourceObject, null), null);
        }
    }
    return targetObject;
}

我想在F#中实现功能等同,所以我做了类似的事情:

member this.AssignMatchingPropertyValues(sourceObject, targetObject)=
    let sourceType = sourceObject.GetType()
    let sourcePropertyInfos = sourceType.GetProperties(BindingFlags.Instance)
    let assignedProperities = sourcePropertyInfos 
                                |> Seq.map(fun spi -> spi, targetObject.GetType().GetProperty(spi.Name))
                                |> Seq.map(fun (spi,tpi) -> tpi.SetValue(targetObject, spi.GetValue(sourceObject,null),null))        
    ()

问题在于它不起作用。我认为b / c的不变性,我正在收集一个新的集合。有没有办法引用原始集合?这是解决这个问题的正确途径吗?

2 个答案:

答案 0 :(得分:4)

以下是您的C#的直接翻译,您的F#代码不是:

let AssignMatchingPropertyValues sourceObject targetObject =
    let sourceType = sourceObject.GetType()
    let targetType = targetObject.GetType()
    let sourcePropertyInfos = sourceType.GetProperties(BindingFlags.Public ||| BindingFlags.Instance)
    for sourcePropertyInfo in sourcePropertyInfos do
        match targetType.GetProperty(sourcePropertyInfo.Name) with
        | null -> ()
        | targetPropertyInfo -> targetPropertyInfo.SetValue(targetObject, sourcePropertyInfo.GetValue(sourceObject, null), null)
    targetObject

答案 1 :(得分:3)

Seq.map很懒,你不会在任何地方进行评估。您可以使用Seq.iter

sourcePropertyInfos 
    |> Seq.map(fun spi -> spi, targetObject.GetType().GetProperty(spi.Name))
    |> Seq.iter(fun (spi,tpi) -> tpi.SetValue(targetObject, spi.GetValue(sourceObject,null),null))