3

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" ?

Dork
  • 1,816
  • 9
  • 29
  • 57
  • 2
    Why would you have two classes that are exactly the same? When the have the same names and types they represent the same thing. When they have different methods you should use inhetitance. – Marco Aug 31 '13 at 17:15
  • It's a very curious idea, why would you do that ? (btw you can't do `a.x=5` since it's private) – Benoit Blanchon Aug 31 '13 at 17:15
  • You can end up forced to do this if you have objects mapped to a specific EF context but happen to have a duplicate database (think staging vs production db's). Not saying it's his case, just a place that knowing this would be useful. – siva.k Aug 31 '13 at 17:26
  • @Marco I have LINQ request which processes .CSV file. And I can make resulting collection of Anonymous type similar to class I use. And I want to copy result of querry into it. – Dork Aug 31 '13 at 17:57
  • Then why using an anonymous class when you could use your class ? – Benoit Blanchon Aug 31 '13 at 18:06
  • @BenoitBlanchon You are right. I just became curious about general case in that moment. – Dork Aug 31 '13 at 18:14

5 Answers5

4

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);
Mathias Müller
  • 22,203
  • 13
  • 58
  • 75
Kirill Bestemyanov
  • 11,946
  • 2
  • 24
  • 38
3

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));
    }
}
I4V
  • 34,891
  • 6
  • 67
  • 79
iamkrillin
  • 6,798
  • 1
  • 24
  • 51
  • 2
    I suggest you don't, because it's freaking slow. – user541686 Aug 31 '13 at 17:57
  • @Mehrdad 10k iterations using reflection = 14 ms, 10k itterations with automapper = 128 ms. So I agree if by slow you mean 10x faster than the accepted answer – iamkrillin Aug 31 '13 at 22:09
  • Uh, I never said the accepted answer was better, did I...? Look at my answer instead, dynamic code generation is the efficient way to do it. – user541686 Sep 01 '13 at 00:38
0

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));
}
user541686
  • 205,094
  • 128
  • 528
  • 886
0

Also you can use Json.NET:

A a = new A();
string s = JsonConvert.SerializeObject(a);
B b = JsonConvert.DeserializeObject<B>(s);
Vladimir
  • 7,345
  • 4
  • 34
  • 39
-1

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

See example in Marshal.StructureToPtr Method (MSDN)

Benoit Blanchon
  • 13,364
  • 4
  • 73
  • 81