4

I have a class which normally contains Fields, Properties. What i want to achieve is instead of this:

class Example
{
    public string Field = "EN";
    public string Name { get; set; }
    public int? Age { get; set; }
    public List<string> A_State_of_String { get; set; }
}

public static void Test()
{
    var c1 = new Example
    {
        Name = "Philip",
        Age = null,
        A_State_of_String = new List<string>
        {
            "Some Strings"
        }
    };
    var c2 = new Example();

    //Instead of doing that
    c2.Name = string.IsNullOrEmpty(c1.Name) ? "" : c1.Name;
    c2.Age = c1.Age ?? 0;
    c2.A_State_of_String = c1.A_State_of_String ?? new List<string>();

    //Just do that
    c1.CopyEmAll(c2);
}

What i came up with but doesn't work as expected.

public static void CopyEmAll(this object src, object dest)
{
    if (src == null) {
        throw new ArgumentNullException("src");
    }

    foreach (PropertyDescriptor item in TypeDescriptor.GetProperties(src)) {
        var val = item.GetValue(src);
        if (val == null) {
            continue;
        }
        item.SetValue(dest, val);
    }
}

Problems:

  • Although i checked for null, it seems to bypass it.
  • Doesn't seem to copy Fields.

Notes:

  • I don't want to use AutoMapper for some technical issues.
  • I want the method to copy values and not creating new object. [just mimic the behavior i stated in the example]
  • I want the function to be recursive [if the class contains another classes it copies its values too going to the most inner one]
  • Don't want to copy null or empty values unless i allow it to.
  • Copies all Fields, Properties, or even Events.
Roman Ratskey
  • 5,101
  • 8
  • 44
  • 67
  • For copying fields you have to use fields collection item.GetType().GetFields() – Michael Feb 14 '14 at 02:33
  • @VMA: can you provide an answer, also i don't want it to be recursive so it do the same for each all childs. – Roman Ratskey Feb 14 '14 at 02:34
  • @VMA: i am so sorry but can you look at the notes again, i updated them to have all my requirements. And please if you can help do it cause i spend the last 3 days trying with no luck, – Roman Ratskey Feb 14 '14 at 02:37
  • Sorry, but I do not understand. You want 'the method to copy values and not creating new object' and at the same time 'the function to be recursive'. If you copy an object to the another class it means you pass it reference, all fields will be the same. – Michael Feb 14 '14 at 02:47
  • i want to pass every things as a reference to the destination as if you are just doing `object1 = object2`. – Roman Ratskey Feb 14 '14 at 02:49
  • @VMA so after the methods finished the destination is fully referenced to the source. – Roman Ratskey Feb 14 '14 at 02:49
  • From the link below you can find how to deal with event handlers. http://stackoverflow.com/questions/293007/is-it-possible-to-steal-an-event-handler-from-one-control-and-give-it-to-anoth – Michael Feb 14 '14 at 02:55
  • possible duplicate of [How do you do a deep copy an object in .Net (C# specifically)?](http://stackoverflow.com/questions/129389/how-do-you-do-a-deep-copy-an-object-in-net-c-specifically) – Aaronaught Feb 14 '14 at 02:55
  • @Aaronaught: I think in my situation here what i need is shallow copy not deep copy. – Roman Ratskey Feb 14 '14 at 02:57
  • Other similar/dupe questions: [Deep cloning objects in C#](http://stackoverflow.com/q/78536); [how to deep copy a class without marking it as serializable](http://stackoverflow.com/q/2545025); [Deep Copy in C#](http://stackoverflow.com/q/8651723) – Aaronaught Feb 14 '14 at 02:58
  • @RuneS: Shallow copy is not recursive and there is already a built-in method for it (`MemberwiseClone`). – Aaronaught Feb 14 '14 at 02:59
  • @Aaronaught: The problem i am facing is very complicated and i wished i could have an answer for it here :(. – Roman Ratskey Feb 14 '14 at 03:05
  • @RuneS: I'll bet the problem is not as complicated as you think it is. For one thing, you haven't described to anyone *why* you need to do this, which smells of an [XY Problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). Why don't you tell us what you really need to do, as opposed to how you want to do it? – Aaronaught Feb 17 '14 at 01:07

2 Answers2

7

Based on Leo's answer, but using Generics and copying also the fields:

public void CopyAll<T>(T source, T target)
{
    var type = typeof(T);
    foreach (var sourceProperty in type.GetProperties())
    {
        var targetProperty = type.GetProperty(sourceProperty.Name);
        targetProperty.SetValue(target, sourceProperty.GetValue(source, null), null);
    }
    foreach (var sourceField in type.GetFields())
    {
        var targetField = type.GetField(sourceField.Name);
        targetField.SetValue(target, sourceField.GetValue(source));
    }       
}

And then just:

CopyAll(f1, f2);
thepirat000
  • 12,362
  • 4
  • 46
  • 72
  • Is it recursive, also doesn't copy null, or empty values ? – Roman Ratskey Feb 14 '14 at 02:42
  • i want the methods to check if the Property is a class then Do the same for it. – Roman Ratskey Feb 14 '14 at 02:43
  • 1
    @RuneS: You're going to find yourself in a world of pain if you're trying to do a "deep copy". How will you deal with circular references? Collection types? Deferred/lazy evaluation and enumerables? If there were straightforward answers for this kind of thing, it would already be implemented as a framework method. – Aaronaught Feb 14 '14 at 02:45
  • 1
    @Aaronaught : collections, and enumerables doesn't have to be deeply copied in my situation. – Roman Ratskey Feb 14 '14 at 02:47
  • @RuneS: That's not consistent with your stated requirements and suggests to me that you need to spend more time thinking it through. If you don't deep copy the collection, then you also don't deep copy any of the elements *in* the collection, which means you'll be using inconsistent rules for objects of (potentially) the exact same type. Anyway, your question has been asked many times before here. – Aaronaught Feb 14 '14 at 02:55
0

You can use serialization to serialize object A and deserialize as object B - if they have very same structure, you can look here for object deep copy. Deep cloning objects

I know you don't want to use Automapper, but if the types have only SIMILAR structure, you should maybe use Automapper which is based on reflection. You can download a nuget and find some information here: https://www.nuget.org/packages/AutoMapper/

your code then will look like

public TOutput CopyAll<TInput, TOutput>(TInput input)
{
    var config = new MapperConfiguration(cfg => cfg.CreateMap<TInput, TOutput>());
    IMapper mapper = config.CreateMapper();
    return mapper.Map<TOutput>(vstup);
}
Jiří Herník
  • 2,412
  • 1
  • 25
  • 26