Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ssis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 映射同一类型的两个对象(不包括某些字段)的最佳方法是什么?_C#_Reflection_Mapping - Fatal编程技术网

C# 映射同一类型的两个对象(不包括某些字段)的最佳方法是什么?

C# 映射同一类型的两个对象(不包括某些字段)的最佳方法是什么?,c#,reflection,mapping,C#,Reflection,Mapping,我之前已经发布了我的问题,但我没有得到任何回复,因为我想这太笼统了。我会尽量简明扼要 我有两个相同类型的对象,我想映射一些属性并排除其他属性。我试图做的是将一个对象保存在缓存中,稍后再获取它,只使用具有特定属性的属性(字段) 我已经看过Automapper,但是我没有发现任何适合我的东西,所以我想实现我自己的系统。 我创建了一个属性: [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = fal

我之前已经发布了我的问题,但我没有得到任何回复,因为我想这太笼统了。我会尽量简明扼要

我有两个相同类型的对象,我想映射一些属性并排除其他属性。我试图做的是将一个对象保存在缓存中,稍后再获取它,只使用具有特定属性的属性(字段)

我已经看过Automapper,但是我没有发现任何适合我的东西,所以我想实现我自己的系统。
我创建了一个属性:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class FilterFieldAttribute: Attribute
{
} 
并在我需要包括的字段上用它装饰了一个类:

public class OrdersViewModel : BaseViewModel
{
...

    [FilterField]
    [DisplayName("Order Number:")]
    public string OrderNumber { get; set; }

    [FilterField]
    [DisplayName("From date:")]
    public DateTime FromDate { get; set; }

    [FilterField]
    [DisplayName("To date:")]
    public DateTime ToDate { get; set; }

    [DisplayName("Status:")]
    public int Status { get; set; }

    ...
} 
现在,我实现了一个负责映射的函数:

    private T Map<T>(T Source, T Destination) where T : BaseViewModel
    {
        if (Source == null)
        {
            return (Source);
        }

        FilterFieldAttribute filterAttribute;

        foreach (PropertyInfo propInfo in typeof(T).GetProperties())
        {
            foreach (FilterFieldAttribute attr in propInfo.GetCustomAttributes(typeof(FilterFieldAttribute), false))
            {
                filterAttribute = attr as FilterFieldAttribute;
                if (filterAttribute != null)
                {
                    var value = propInfo.GetValue(Source, null);
                    propInfo.SetValue(Destination, value, null);
                }
            }
        }
        return (Destination);
    }
私有T映射(T源,T目的地),其中T:BaseViewModel
{
if(Source==null)
{
返回(来源);
}
FilterFieldAttribute filterAttribute;
foreach(typeof(T).GetProperties()中的PropertyInfo-propInfo)
{
foreach(propInfo.GetCustomAttributes中的FilterFieldAttribute属性属性(typeof(FilterFieldAttribute),false))
{
filterAttribute=attr作为FilterFieldAttribute;
如果(filterAttribute!=null)
{
var value=propInfo.GetValue(源,空);
设置值(目的地,值,空);
}
}
}
返回(目的地);
}
现在,当我需要从缓存中获取viewmodel并仅填充标记有属性的属性时,我的代码如下所示:

viewModel = Map<T>(myCache.Get(Key) as T, viewModel);
viewModel=Map(myCache.Get(Key)作为T,viewModel);
我不知道这是否是最好的方法,但这似乎是我找到的唯一方法。

如果您有任何建议,我们将不胜感激。

听起来是个好的开始,但您正在失去AutoMapper带来的诸多好处。AutoMapper还可以处理这里没有的嵌套属性(当类包含嵌套映射类时)

由于AutoMapper是一个oprn源代码项目,我建议您使用AutoMapper源代码并在那里实现过滤。这实际上也对其他人有用。

使用直接反射(如示例中所示)将是斯洛;给出一个更完整的答案很棘手,因为这取决于您想要的是子对象的浅克隆还是深克隆。无论哪种方式,您都应该期望这涉及一些元编程和缓存—使用ILGenerator或表达式

但是,对于惰性选项,序列化可能很有用。许多序列化程序允许您使用属性包括/排除特定项;通过序列化到内存流、倒带(
.Position=0
)和反序列化,您应该只获得所选成员的深度副本

下面是一个使用
表达式的示例:

using System;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class FilterFieldAttribute: Attribute
{
    public static T Clone<T>(T obj) where T : class, new()
    {
        return Cache<T>.clone(obj);
    }

    private static class Cache<T> where T : class, new()
    {
        public static readonly Func<T,T> clone;
        static Cache()
        {
            var param = Expression.Parameter(typeof(T), "source");
            var members = from prop in typeof(T).GetProperties()
                          where Attribute.IsDefined(prop, typeof(FilterFieldAttribute))
                          select Expression.Bind(prop, Expression.Property(param, prop));

            var newObj = Expression.MemberInit(Expression.New(typeof(T)), members);
            clone = Expression.Lambda<Func<T,T>>(newObj, param).Compile();
        }
    }
} 

public class OrdersViewModel 
{
    [FilterField]
    [DisplayName("Order Number:")]
    public string OrderNumber { get; set; }

    [FilterField]
    [DisplayName("From date:")]
    public DateTime FromDate { get; set; }

    [FilterField]
    [DisplayName("To date:")]
    public DateTime ToDate { get; set; }

    [DisplayName("Status:")]
    public int Status { get; set; }

    static void Main()
    {
        var foo = new OrdersViewModel { OrderNumber = "abc", FromDate = DateTime.Now,
            ToDate = DateTime.Now, Status = 1};
        var bar = FilterFieldAttribute.Clone(foo);
    }
}
使用系统;
使用系统组件模型;
使用System.Linq;
使用System.Linq.Expressions;
[AttributeUsage(AttributeTargets.Property,AllowMultiple=false,Inherited=false)]
公共类FilterFieldAttribute:属性
{
公共静态T克隆(T obj),其中T:class,new()
{
返回Cache.clone(obj);
}
私有静态类缓存,其中T:class,new()
{
公共静态只读功能克隆;
静态缓存()
{
var param=表达式参数(类型(T),“源”);
var members=来自typeof(T).GetProperties()中的prop
其中定义了Attribute.IsDefined(prop,typeof(FilterFieldAttribute))
选择Expression.Bind(prop,Expression.Property(param,prop));
var newObj=Expression.MemberInit(Expression.New(typeof(T)),成员);
clone=Expression.Lambda(newObj,param.Compile();
}
}
} 
公共类OrdersViewModel
{
[过滤场]
[显示名称(“订单号:”)]
公共字符串OrderNumber{get;set;}
[过滤场]
[显示名称(“起始日期:)]
公共日期时间FromDate{get;set;}
[过滤场]
[显示名称(“到目前为止:)]
公共日期时间ToDate{get;set;}
[显示名称(“状态:”)]
公共int状态{get;set;}
静态void Main()
{
var foo=newordersviewmodel{OrderNumber=“abc”,FromDate=DateTime.Now,
ToDate=DateTime.Now,Status=1};
var bar=FilterFieldAttribute.Clone(foo);
}
}

我认为你的方法还可以。反射对性能有一些影响,这是值得考虑的

另一种性能更好、更简单的方法可能是让BaseViewModel定义一个抽象方法:

public abstract BaseViewModel ToCacheVersion();
它可用于将子类转换为正确的类型。每个子类将负责自己的映射:

public class ViewModelX
{
    public ViewModelX(string name, string description)
    {
        Name = name;
        Description = description;
    }

    ...

    public override BaseViewModel ToCacheVersion()
    {
        return new ViewModelX(
            Name, // Include the name.
            null  // Ignore the description.
        );
    }

    ...
}

谢谢你的回答。我已经在使用Automapper,但我不知道如何做我正在尝试做的事情(我正在使用一个基类,因为我想让所有东西都“通用”)。我试图只映射几个字段(搜索字段),因此我不需要真正地映射到嵌套类中。@LeftyX有关简单的平面绑定,请参阅使用表达式now addedMarc的示例,谢谢您的回复。我只想映射/复制几个字段。我不需要映射嵌套类。出于这些目的,我已经使用Automapper。这里的问题是我想缓存一些字段,稍后再检索,避免那些没有属性的字段。