简体   繁体   English

将Entity对象复制到POCO对象,其中Entity int是POCO上的Enums

[英]Copy Entity object to POCO object where Entity ints are Enums on the POCO

I'm attempting to create a copier using Jon Skeets property copy. 我正在尝试使用Jon Skeets属性副本创建复印机。 It works fine for all properties, but not enums. 它适用于所有属性,但不能枚举。 I've tried several attempts at changing the method to work for enums to little success. 我已经尝试过几次尝试,以更改为枚举工作的方法,但收效甚微。 I was wondering if anyone else might have an idea on how to do this. 我想知道是否还有其他人对此有一个想法。

Jon Skeets original, with my alterations sectioned off with comments in the BUILDCOPIER method Jon Skeets原创,我的修改内容以BUILDCOPIER方法中的注释分开

calls to this are 对此的呼吁

        var result = Common.PropertyCopy<POCO>.CopyFrom(Entity);

Original Jon Skeet code 原始的Jon Skeet代码

/// <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.
/// http://www.yoda.arachsys.com/csharp/miscutil/
/// </summary>
public static 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);
                }

                // THIS IS FALSE FOR SOURCE(INT) TARGET ENUMS
                if (!targetProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType))
                {
                    //ADDED FOLLOWING TO HANDLE COPY FROM INT TO ENUM
                    /////////////////////////////////////////////////////////////////////////////////////////////////////
                    // Special Case because Entities are created with property as ints, not enum types
                    if (targetProperty.PropertyType.IsEnum && (sourceProperty.PropertyType == typeof(int)))
                    {
                        var expressionparam = Expression.Parameter(sourceProperty.PropertyType);
                        // cast the entity source as the enum target
                        var cast = Expression.Convert(expressionparam, targetProperty.PropertyType);
                        // add to the binding tree
                        bindings.Add(Expression.Bind(targetProperty, Expression.Property(cast, sourceProperty)));
                        continue;
                    }
                    /////////////////////////////////////////////////////////////////////////////////////////////////////

                    throw new ArgumentException("Property " + sourceProperty.Name + " has an incompatible type in " + typeof(TTarget).FullName);
                }
            Expression initializer = Expression.MemberInit(Expression.New(typeof(TTarget)), bindings);
            return Expression.Lambda<Func<TSource, TTarget>>(initializer, sourceParameter).Compile();
        }
    }
}

Enum 枚举

public enum NotificationType
{
    InAppNotificiation = 0,
    EmailNotification,
    SMS
}

Entity Class generated by EF EF生成的实体类

public class Entity
{
    public int ProcessedStatus { get; set; }
    public int Priority { get; set; }
    public System.Guid NotifyToUserId { get; set; }
    public string NotifyFrom { get; set; }
    public string NotifySubject { get; set; }
    public string NotifyMessageBody { get; set; }
    public int NotificationType { get; set; }  <-- Stored as int in DB

     public virtual MercuryUser MercuryUser { get; set; } <--complex type
}

POCO Class POCO类

public class POCO
{
    public int ProcessedStatus { get; set; }
    public int Priority { get; set; }
    public System.Guid NotifyToUserId { get; set; }
    public string NotifyFrom { get; set; }
    public string NotifySubject { get; set; }
    public string NotifyMessageBody { get; set; }
    public NotificationType NotificationType { get; set; }  <-- ENUM TYPE

    public MyUser MyUser { get; set; } <-- complex type
}

Exception thrown at the line 抛出异常

bindings.Add(Expression.Bind(targetProperty, Expression.Property(cast, sourceProperty)));

Property 'Int32 NotificationType' is not defined for type 'Models.Enums.NotificationType 未为类型“ Models.Enums.NotificationType”定义属性“ Int32 NotificationType”

So I found this post C# Using Reflection to copy base class properties and tried this instead, sometimes simple just works... not sure why this one will set the enum and also not blow up on the complex type. 因此,我发现了这篇文章C#Using Reflection复制基类的属性并尝试了它,有时简单的方法就行了……不知道为什么这会设置枚举而不会使复杂的类型崩溃。 Perhaps its how the lambda expression interprets the object. 也许是lambda表达式如何解释对象。 It doesn't check the is assignable from for anything, in particular the enum type, it just sets it based on the int and property name. 它不会检查from是可分配的,尤其是枚举类型,它只是根据int和属性名称进行设置。 Kind of counter intuitive if isAssignable says NO when trying to set from a sourceproperty of type int and a targetproperty of type enum when the underlying types are the same. 如果isAssignable在基础类型相同时尝试从int类型的sourceproperty和enum类型的targetproperty设置时,如果isAssignable表示NO,则有点直观。 If anyone can shed some insight into this that would be great, for now I'm going to use the simpler method of copy listed below. 如果有人可以对此有所了解,那么现在我将使用下面列出的更简单的复制方法。 Down side is it doesn't cache the copier so it has to go through it every time. 不利的一面是它不缓存复印机,因此每次都必须经过它。

    public static T1 CopyFrom<T1, T2>(T1 obj, T2 otherObject) where T1 : class where T2 : class
    {
        PropertyInfo[] srcFields = otherObject.GetType().GetProperties(
            BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty);

        PropertyInfo[] destFields = obj.GetType().GetProperties(
            BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty);

        foreach (var property in srcFields)
        {
            var dest = destFields.FirstOrDefault(x => x.Name == property.Name);
            if (dest != null && dest.CanWrite)
                dest.SetValue(obj, property.GetValue(otherObject, null), null);
        }

        return obj;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM