0

可能重复:
在 C# 中克隆对象

我想要做的是将类中的值从一个对象复制到另一个对象。浅拷贝就好了。但是,我不想丢失对象对列表/array/ienumerable 的引用。另外,我也不想这样做:

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;
}

反而:

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

3 回答 3

1

你可以这样做

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

如果您更喜欢使用强类型方法,只需忘记接口

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

这不会将一个对象的字段复制到另一个对象,而是创建一个与原始对象完全相同的新对象。它制作了一个浅拷贝。

于 2012-04-20T20:29:48.593 回答
1

这是我今天写的代码。它通过了简单的测试。我想你可以用它来开始。

这是测试:

    /// <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; }
    }

这是代码:

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;
    }
}
于 2012-04-20T21:32:32.823 回答
0

你需要Object.MemberwiseClone 方法

于 2012-04-20T20:28:51.480 回答