How to copy value from class X to class Y with the same property name in c#?

后端 未结 5 735
灰色年华
灰色年华 2020-11-28 08:49

Suppose I have two classes:

public class Student
{
    public int Id {get; set;}
    public string Name {get; set;}
    public IList Courses{ g         


        
相关标签:
5条回答
  • 2020-11-28 09:24

    There's a library for doing just that - http://emitmapper.codeplex.com/

    It's much faster than AutoMapper, it uses System.Reflection.Emit, so the code runs almost as fast as if it was hand-written.

    0 讨论(0)
  • 2020-11-28 09:25

    Ok I just looked up the MiscUtil that Marc posted about and its just awesome. I hope mark doesn't mind me adding the code here.

    using System;
    using System.Collections;
    using System.Collections.Specialized;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Reflection;
    using System.ComponentModel;
    using System.Linq.Expressions;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            public class Student
            {
                public int Id { get; set; }
                public string Name { get; set; }
                public IList<int> Courses { get; set; }
                public static implicit operator Student(StudentDTO studentDTO)
                {
                    return PropertyCopy<Student>.CopyFrom(studentDTO);
                }
            }
    
            public class StudentDTO
            {
                public int Id { get; set; }
                public string Name { get; set; }
                public IList<int> Courses { get; set; }
                public static implicit operator StudentDTO(Student student)
                {
                    return PropertyCopy<StudentDTO>.CopyFrom(student);
                }
            }
    
    
            static void Main(string[] args)
            {
                Student _student = new Student();
                _student.Id = 1;
                _student.Name = "Timmmmmmmmaaaahhhh";
                _student.Courses = new List<int>();
                _student.Courses.Add(101);
                _student.Courses.Add(121);
    
                StudentDTO itemT = _student;
    
                Console.WriteLine(itemT.Id);
                Console.WriteLine(itemT.Name);
                Console.WriteLine(itemT.Courses.Count);
            }
    
    
        }
    
    
        // COOLEST PIECE OF CODE FROM - http://www.yoda.arachsys.com/csharp/miscutil/
    
        /// <summary>
        /// Generic class which copies to its target type from a source
        /// type specified in the Copy method. The types are specified
        /// separately to take advantage of type inference on generic
        /// method arguments.
        /// </summary>
        public class PropertyCopy<TTarget> where TTarget : class, new()
        {
            /// <summary>
            /// Copies all readable properties from the source to a new instance
            /// of TTarget.
            /// </summary>
            public static TTarget CopyFrom<TSource>(TSource source) where TSource : class
            {
                return PropertyCopier<TSource>.Copy(source);
            }
    
            /// <summary>
            /// Static class to efficiently store the compiled delegate which can
            /// do the copying. We need a bit of work to ensure that exceptions are
            /// appropriately propagated, as the exception is generated at type initialization
            /// time, but we wish it to be thrown as an ArgumentException.
            /// </summary>
            private static class PropertyCopier<TSource> where TSource : class
            {
                private static readonly Func<TSource, TTarget> copier;
                private static readonly Exception initializationException;
    
                internal static TTarget Copy(TSource source)
                {
                    if (initializationException != null)
                    {
                        throw initializationException;
                    }
                    if (source == null)
                    {
                        throw new ArgumentNullException("source");
                    }
                    return copier(source);
                }
    
                static PropertyCopier()
                {
                    try
                    {
                        copier = BuildCopier();
                        initializationException = null;
                    }
                    catch (Exception e)
                    {
                        copier = null;
                        initializationException = e;
                    }
                }
    
                private static Func<TSource, TTarget> BuildCopier()
                {
                    ParameterExpression sourceParameter = Expression.Parameter(typeof(TSource), "source");
                    var bindings = new List<MemberBinding>();
                    foreach (PropertyInfo sourceProperty in typeof(TSource).GetProperties())
                    {
                        if (!sourceProperty.CanRead)
                        {
                            continue;
                        }
                        PropertyInfo targetProperty = typeof(TTarget).GetProperty(sourceProperty.Name);
                        if (targetProperty == null)
                        {
                            throw new ArgumentException("Property " + sourceProperty.Name + " is not present and accessible in " + typeof(TTarget).FullName);
                        }
                        if (!targetProperty.CanWrite)
                        {
                            throw new ArgumentException("Property " + sourceProperty.Name + " is not writable in " + typeof(TTarget).FullName);
                        }
                        if (!targetProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType))
                        {
                            throw new ArgumentException("Property " + sourceProperty.Name + " has an incompatible type in " + typeof(TTarget).FullName);
                        }
                        bindings.Add(Expression.Bind(targetProperty, Expression.Property(sourceParameter, sourceProperty)));
                    }
                    Expression initializer = Expression.MemberInit(Expression.New(typeof(TTarget)), bindings);
                    return Expression.Lambda<Func<TSource,TTarget>>(initializer, sourceParameter).Compile();
                }
            }
        }
    
    }
    
    0 讨论(0)
  • 2020-11-28 09:26

    FYI

    When I was having the same question I found AutoMapper (http://automapper.codeplex.com/) Then after reading AboutDev's answer i was done some simple test, the results pretty impressive

    here the test results:

    Test Auto Mapper:22322 ms

    Test Implicit Operator:310 ms

    Test Property Copy:250 ms

    Test Emit Mapper:281 ms

    And i would like to underline that it is sample only with classes(StudentDTO, Student) which have only a couple of properties, but what would happened if classes would have 50 - 100 properties, i guess it will affect performance dramatically.

    More tests details here: Object copy approaches in .net: Auto Mapper, Emit Mapper, Implicit Operation, Property Copy

    0 讨论(0)
  • 2020-11-28 09:39

    The lists make it tricky... my earlier reply (below) only applies to like-for-like properties (not the lists). I suspect you might just have to write and maintain code:

        Student foo = new Student {
            Id = 1,
            Name = "a",
            Courses = {
                new Course { Key = 2},
                new Course { Key = 3},
            }
        };
        StudentDTO dto = new StudentDTO {
            Id = foo.Id,
            Name = foo.Name,
        };
        foreach (var course in foo.Courses) {
            dto.Courses.Add(new CourseDTO {
                Key = course.Key
            });
        }
    

    edit; only applies to shallow copies - not lists

    Reflection is an option, but slow. In 3.5 you can build this into a compiled bit of code with Expression. Jon Skeet has a pre-rolled sample of this in MiscUtil - just use as:

    Student source = ...
    StudentDTO item = PropertyCopy<StudentDTO>.CopyFrom(student);
    

    Because this uses a compiled Expression it will vastly out-perform reflection.

    If you don't have 3.5, then use reflection or ComponentModel. If you use ComponentModel, you can at least use HyperDescriptor to get it nearly as quick as Expression

    Student source = ...
    StudentDTO item = new StudentDTO();
    PropertyDescriptorCollection
         sourceProps = TypeDescriptor.GetProperties(student),
         destProps = TypeDescriptor.GetProperties(item),
    foreach(PropertyDescriptor prop in sourceProps) {
        PropertyDescriptor destProp = destProps[prop.Name];
        if(destProp != null) destProp.SetValue(item, prop.GetValue(student));
    }
    
    0 讨论(0)
  • 2020-11-28 09:44

    Write a implicit operator in anyone class

        public static implicit operator StudentDTO(Student student)
        {
    
            //use skeet's library
    
            return PropertyCopy<StudentDTO>.CopyFrom(student);
    
        }
    

    now you can do that

    StudentDTO studentDTO = student;
    
    0 讨论(0)
提交回复
热议问题