Sen Jacob
Sen Jacob

Reputation: 3452

How to assign C# dynamic variable properties to another dynamic object?

I'm trying to write a function which creates an object of Type t and assign its properties.

    internal static object CreateInstanceWithParam(Type t, dynamic d)
    {
        //dynamic obj =  t.GetConstructor(new Type[] { d }).Invoke(new object[] { d });

        dynamic obj =  t.GetConstructor(new Type[] { }).Invoke(new object[] { });
        foreach (var prop in d.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
        {
            //prop.Name, 
            //prop.GetValue(d, null);

            // assign the properties and corresponding values to newly created object ???
        }
        return obj;
    }

Then I should be able to use this for any kind of class types like

IUser user = (IUser)CreateInstanceWithParam(userType, new { UserID = 0, Name = "user abc", LoginCode = "abc", DefaultPassword = "xxxxxx" });

IUnit newUnit = (IUnit)CreateInstanceWithParam(unitType, new { ID = 3, Code = "In", Name = "Inch", Points = "72" })

How can I assign the property prop.Name to obj?

Upvotes: 1

Views: 2740

Answers (2)

Marc Gravell
Marc Gravell

Reputation: 1063884

Actually, using dynamic would probably be a bad thing here; the objects you are passing in are instances of anonymous types - no need for dynamic. In particular, dynamic member access is not the same as reflection, and you cannot guarantee that an object described as dynamic will return anything interesting from .GetType().GetProperties(); consider ExpandoObject, etc.

However, FastMember (available on NuGet) may be useful:

internal static object CreateInstanceWithParam(Type type, object template)
{
    TypeAccessor target = TypeAccessor.Create(type),
        source = TypeAccessor.Create(template.GetType());
    if (!target.CreateNewSupported)
            throw new InvalidOperationException("Cannot create new instance");
    if (!source.GetMembersSupported)
            throw new InvalidOperationException("Cannot enumerate members");
    object obj = target.CreateNew();
    foreach (var member in source.GetMembers())
    {
        target[obj, member.Name] = source[template, member.Name];
    }
    return obj;
}

In particular, this can use the dynamic API just as easily as the reflection API, and you never usually see the difference.

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1503140

Assuming you're just trying to copy properties, you don't need dynamic at all:

internal static object CreateInstanceWithParam(Type type, object source)
{
    object instance = Activator.CreateInstance(type);
    foreach (var sourceProperty in d.GetType()
                                    .GetProperties(BindingFlags.Instance | 
                                                   BindingFlags.Public))
    {
        var targetProperty = type.GetProperty(sourceProperty.Name);
        // TODO: Check that the property is writable, non-static etc
        if (targetProperty != null)
        {
            object value = sourceProperty.GetValue(source);
            targetProperty.SetValue(instance, value);
        }
    }
    return instance;
}

Upvotes: 3

Related Questions