Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assigning Property values using System.Reflection in F#

Tags:

f#

I have the following lines of code in 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;
}

I want to implement a functional equivalent in F# so I did something like this:

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))        
    ()

The problem is that it does not work. I think b/c of immutability, I am getting a new collection. Is there a way to ref the original collection? Is this the right path in tackling this problem?

like image 730
Jamie Dixon Avatar asked Jan 29 '26 22:01

Jamie Dixon


2 Answers

Here is a direct translation of your C#, which your F# code is not:

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
like image 63
Daniel Avatar answered Jan 31 '26 12:01

Daniel


Seq.map is lazy and you aren't evaluating it anywhere. You can use 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))
like image 27
Lee Avatar answered Jan 31 '26 11:01

Lee



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!