Dork
Dork

Reputation: 1886

Is it possible to copy instances of types with similar fields?

Let's say we have two classes with same names and types of fields:

class A
 {
  private int x;
  private string y;
 }

class B
 {
  private int x;
  private string y;
 }

A a = new A();
B b = new B();
a.x = 5;
a.y = "xxx";

Is it possible to "copy" or "assign" a into b? I mean is there simple way to do it like "b=a" ?

Upvotes: 3

Views: 266

Answers (5)

Kirill Bestemyanov
Kirill Bestemyanov

Reputation: 11964

The simplest way to do what you want is to use the Automapper library.

In this case you add map for these two classes:

Mapper.CreateMap<A,B>();

and then use method Map:

A a = new A();
//initialize a
B b = Mapper.Map(a);

Upvotes: 4

Vladimir
Vladimir

Reputation: 7475

Also you can use Json.NET:

A a = new A();
string s = JsonConvert.SerializeObject(a);
B b = JsonConvert.DeserializeObject<B>(s);

Upvotes: 1

user541686
user541686

Reputation: 210352

There's no simple way to do it in C#.
You can, however, dynamically generate your own methods via ILGenerator or Expression Trees to do this copying for you. (It's not easy if you haven't done it before though.)

Example:

using System;
using System.Reflection;
using System.Reflection.Emit;

public class Foo
{
    private int a;
    public Foo(int a) { this.a = a; }
}

public class Program
{
    private int a;
    private static void Main()
    {
        var prog1 = new Foo(1);
        var prog2 = new Program() { a = 2 };
        TypeHelper<Foo, Program>.Copy(prog1, prog2);
    }
}

public static class TypeHelper<T1, T2> where T1 : class where T2: class
{
    public delegate void CopyAction(T1 from, T2 to);
    public static readonly CopyAction Copy = new Converter<Type, CopyAction>(t1 =>
    {
        var method = new DynamicMethod(string.Empty, null, new Type[] { t1, typeof(T2) }, t1, true);
        var gen = method.GetILGenerator();
        foreach (var field in t1.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
        {
            gen.Emit(OpCodes.Ldarg_1);
            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Ldfld, field);
            gen.Emit(OpCodes.Stfld, typeof(T2).GetField(field.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic));
        }
        return (CopyAction)method.CreateDelegate(typeof(CopyAction));
    })(typeof(T1));
}

Upvotes: 0

iamkrillin
iamkrillin

Reputation: 6876

I'd suggest you use reflection:

void Main()
{
    A foo = new A();
    B bar = new B();

    CopyValues(foo, bar);
}

public void CopyValues(object f, object t)
{
    Type fr = f.GetType();
    Type target = t.GetType();

    var bindingFlags = BindingFlags.Public| BindingFlags.NonPublic | BindingFlags.Instance;

    foreach(FieldInfo source in fr.GetFields(bindingFlags))
    {
        FieldInfo fi = target.GetField(source.Name, bindingFlags);
        if(fi != null)
            fi.SetValue(t, source.GetValue(f));
    }
}

Upvotes: 3

Benoit Blanchon
Benoit Blanchon

Reputation: 14511

I think you can do that with Marshal.StructureToPtr and Marshal.PtrToStructure.

See example in Marshal.StructureToPtr Method (MSDN)

Upvotes: -1

Related Questions