Is there an Object1.CopyTo(Object2) method in .NET?

Possible Duplicate:
Cloning objects in C#

What I want to do is copy the values in a class from one object to another. Shallow Copy is just fine. However, I do not want to lose the reference that object has to the list /array/ienumerable. Also, I don't want to want to do this either:

public static void EditEvent(EventModel editEvent)
{
    EventModel changingEvent = EventRepository.getEvent(editEvent.EventID);
    changingEvent.Subject = editEvent.Subject;
    changingEvent.EventDate = editEvent.EventDate;
    changingEvent.EventDesc = editEvent.EventDesc;
    changingEvent.DayCode = editEvent.DayCode;
}

But rather:

public static void EditEvent(EventModel editEvent)
{
    EventModel changingEvent = EventRepository.getEvent(editEvent.EventID);
    changingEvent.CopyFrom(editEvent);
    //or
    editEvent.CopyTo(changingEvent);
}

This is code I wrote today. It passes simple tests. I'm thinking you can use it to get started.

Here is the test:

    /// <summary>
    ///A test for MapProperties
    ///</summary>
    public void MapPropertiesTestHelper<S, T>(S source, T target1, bool failIfNotMatched)
    {
        Cake.Common.Mapper<S, T> target = new Cake.Common.Mapper<S, T>();
        target.MapProperties(source, target1, failIfNotMatched);
    }

    [TestMethod()]
    public void MapPropertiesTest()
    {
        var source = new Source {
            OneTwo = 10,
            ThreeFour = "foo"
        };

        var target = new Target {
            OneTwo = 10,
            ThreeFour = "bar"
        };

        MapPropertiesTestHelper<Source, Target>(source, target, true);

        Assert.AreEqual(source.OneTwo, target.OneTwo);
        Assert.AreEqual(source.ThreeFour, target.ThreeFour);
        Assert.AreEqual(source.five_six, target.FiveSix);
    }

    public class Source
    {
        public int OneTwo { get; set; }
        public string ThreeFour { get; set; }
        public bool five_six { get; set; }
    }

    public class Target
    {
        public int OneTwo { get; set; }
        public string ThreeFour { get; set; }
        public bool FiveSix { get; set; }
    }

And here is the code:

public class MapperItem
{
    public MapperItem(MemberInfo member, object o)
    {
        this.Member = member;
        this.Object = o;
    }

    public MemberInfo Member 
    { 
        get; 
        set; 
    }

    public object Object
    {
        get;
        set;
    }

    public Type Type
    {
        get
        {
            return this.Member.UnderlyingType();
        }
    }

    public object Value
    {
        get
        {
            if (this.Member is PropertyInfo)
            {
                return (this.Member as PropertyInfo).GetValue(this.Object, null);
            }
            else if (this.Member is FieldInfo)
            {
                return (this.Member as FieldInfo).GetValue(this.Object);
            }
            else
            {
                throw new Exception("sourceMember must be either PropertyInfo or FieldInfo");
            }
        }
    }

    public object Convert(Type targetType)
    {
        object converted = null;

        if (this.Value == null)
        {
            return converted;
        }
        else if (targetType.IsAssignableFrom(this.Type))
        {
            converted = this.Value;
        }
        else
        {
            var conversionKey = Tuple.Create(this.Type, targetType);
            if (Conversions.ContainsKey(conversionKey))
            {
                converted = Conversions[conversionKey](this.Value);
            }
            else
            {
                throw new Exception(targetType.Name + " is not assignable from " + this.Type.Name);
            }
        }

        return converted;
    }

    public void Assign(object value)
    {
        if (this.Member is PropertyInfo)
        {
            (this.Member as PropertyInfo).SetValue(this.Object, value, null);
        }
        else if (this.Member is FieldInfo)
        {
            (this.Member as FieldInfo).SetValue(this.Object, value);
        }
        else
        {
            throw new Exception("destinationMember must be either PropertyInfo or FieldInfo");
        }
    }

    public static Dictionary<Tuple<Type, Type>, Func<object, object>> Conversions = new Dictionary<Tuple<Type, Type>, Func<object, object>>();
}

public class Mapper<S, T>
{
    private List<string> ignoreList = new List<string>();
    public List<string> IgnoreList
    {
        get { return ignoreList; }
        set { ignoreList = value; }
    }

    public void MapProperties(S source, T target, bool failIfNotMatched = true)
    {
        foreach (PropertyInfo property in source.GetType()
                                                      .GetProperties()
                                                      .Where(c => !IgnoreList.Contains(c.Name)))
        {
            try
            {
                var sourceField = new MapperItem(property, source);
                var targetField = new MapperItem(MatchToTarget(property), target);
                targetField.Assign(sourceField.Convert(targetField.Type));
            }
            catch (TargetNotMatchedException noMatch)
            {
                if (failIfNotMatched)
                {
                    throw noMatch;
                }
            }
        }
    }

    private MemberInfo MatchToTarget(MemberInfo member)
    {
        List<MemberInfo> members = new List<MemberInfo>();
        members.AddRange(typeof(T).GetProperties());
        members.AddRange(typeof(T).GetFields());

        var exactMatch = from c in members where c.Name == member.Name select c;

        if (exactMatch.FirstOrDefault() != null)
        {
            return exactMatch.First();
        }

        var sameAlphaChars = from c in members
                             where NormalizeName(c.Name) == NormalizeName(member.Name)
                             select c;

        if (sameAlphaChars.FirstOrDefault() != null)
        {
            return sameAlphaChars.First();
        }

        throw new TargetNotMatchedException(member, typeof(T));
    }

    private static string NormalizeName(string input)
    {
        string normalized = input.Replace("_", "").ToUpper();
        return normalized;
    }
}

public class TargetNotMatchedException : Exception
{
    public TargetNotMatchedException(MemberInfo member, Type type)
        : base("no match for member named " + member.Name + " with type named " + type.Name)
    {
        this.Member = member;
        this.Type = type;
    }
    public MemberInfo Member { get; set; }
    public Type Type { get; set; }
}

public static class ReflectionExtensions
{
    public static Type UnderlyingType(this MemberInfo member)
    {
        Type type;
        switch (member.MemberType)
        {
            case MemberTypes.Field:
                type = ((FieldInfo)member).FieldType;
                break;
            case MemberTypes.Property:
                type = ((PropertyInfo)member).PropertyType;
                break;
            case MemberTypes.Event:
                type = ((EventInfo)member).EventHandlerType;
                break;
            default:
                throw new ArgumentException("MemberInfo must be if type FieldInfo, PropertyInfo or EventInfo", "member");
        }
        return Nullable.GetUnderlyingType(type) ?? type;
    }
}

You can do it like this

public class MyClonableClass : ICloneable
{
    public object Clone()
    {
        return this.MemberwiseClone();
    }
}

If you prefer to use a strongly typed method, just forget the interface

public class MyClonableClass
{
    public MyClonableClass Clone()
    {
        return (MyClonableClass)this.MemberwiseClone();
    }
}

This does not copy the fields of one object to another, but creates a new object which is an exact duplicate of the original. It makes a shallow copy.


你需要Object.MemberwiseClone方法

链接地址: http://www.djcxy.com/p/40774.html

上一篇: 创建对象的深层副本

下一篇: .NET中是否存在Object1.CopyTo(Object2)方法?