【问题标题】:AutoMapper and is*Specified propertiesAutoMapper 和 is* 指定的属性
【发布时间】:2010-03-09 12:14:22
【问题描述】:

我有一堆 XSD.exe 生成的数据协定类,它们对于所有可选元素都有一对 C# 属性,例如

int Amount {get; set;}
bool isAmountSpecified {get; set;}

在映射领域的另一边,我有一个可以为空的 int,例如

int? Amount {get; set;}

理想情况下,我希望 AutoMapper 能够识别此类模式并知道如何在双向映射事物,而无需我为每个单独的属性指定映射。这可能吗?

【问题讨论】:

  • 我认为这可以帮助valueinjecter.codeplex.com/documentation,你只需要指定一个int到int的映射算法吗?一次并将其用于您需要的任何对象,您不必为每对类型创建映射

标签: c# xsd automapper xsd.exe


【解决方案1】:

好的,昨天我与 AutoMapper 的作者 Jimmy Bogard 进行了简短的讨论,基本上我正在寻找的内容目前是不可能的。对此类约定的支持将在将来的某个时间实施(如果我理解正确的话:))。

【讨论】:

    【解决方案2】:

    老实说,我不知道 AutoMapper 是否会这样做(因为我不经常使用 AutoMapper),但我知道 protobuf-net 支持这两种模式,所以你可以使用 Serializer.ChangeType<,>(obj) 在它们之间切换。

    当前版本非常依赖于成员的属性(例如[XmlElement(Order = n)]) - 我不知道这是否会导致问题? 进行中 版本支持 vanilla 类型(没有属性),但这还不完整(但很快)。

    例子:

    [XmlType]
    public class Foo
    {
        [XmlElement(Order=1)]
        public int? Value { get; set; }
    }
    [XmlType]
    public class Bar
    {
        [XmlElement(Order = 1)]
        public int Value { get; set; }
        [XmlIgnore]
        public bool ValueSpecified { get; set; }
    }
    static class Program
    {
        static void Main()
        {
            Foo foo = new Foo { Value = 123 };
            Bar bar = Serializer.ChangeType<Foo, Bar>(foo);
            Console.WriteLine("{0}, {1}", bar.Value, bar.ValueSpecified);
    
            foo = new Foo { Value = null };
            bar = Serializer.ChangeType<Foo, Bar>(foo);
            Console.WriteLine("{0}, {1}", bar.Value, bar.ValueSpecified);
    
            bar = new Bar { Value = 123, ValueSpecified = true };
            foo = Serializer.ChangeType<Bar, Foo>(bar);
            Console.WriteLine(foo.Value);
    
            bar = new Bar { Value = 123, ValueSpecified = false };
            foo = Serializer.ChangeType<Bar, Foo>(bar);
            Console.WriteLine(foo.Value);
        }
    }
    

    【讨论】:

    • @Marc,感谢您提供的信息 - 我不了解 protobuf-net,我会看看。
    【解决方案3】:

    这里是如何将具有*指定属性(源)的模型映射到具有可为空属性(目标)的模型的示例。 我已经为所有成员配置了 Condition 方法,它将检查源属性是否具有相应的 *Specified 属性,如果有,那么它将检查它的值。如果 *Specified 属性返回false,则不满足条件,将跳过映射。

    您可以在其他方向上执行相同的操作,但您必须设置它而不是读取 *Specified 属性值。

    public void Configure(IMapperConfigurationExpression cfg)
    {
        cfg.CreateMap<Source, Destination>()
            .ForAllOtherMembers(opt => opt.PreCondition((srcObj, context) => IsSpecified(srcObj, context, opt)));
    }
    
    public static bool IsSpecified<TSource, TDestination, TMember>(TSource source, ResolutionContext context, IMemberConfigurationExpression<TSource, TDestination, TMember> opt)
    {
        var dstMemberPropertyInfo = opt.DestinationMember as PropertyInfo;
    
        // if destination member not nullable, then assume that source member won't have *Specified property
        if (!IsNullableType(dstMemberPropertyInfo.PropertyType))
            return true;
    
        var config = context.Mapper.ConfigurationProvider;
        var map = config.FindTypeMapFor<TSource, TDestination>();
        var propertyMap = map.PropertyMaps.FirstOrDefault(x => x.DestinationMember.Name == opt.DestinationMember.Name);
        var sourceMembers = new Queue<MemberInfo>(propertyMap.SourceMembers);
        var srcParentType = typeof(TSource);
        var srcParentObj = source as object;
    
        // get the source parent instance
        while (sourceMembers.Count > 1) // the last item in queue is the SourceMember itself
        {
            var srcParentPropertyInfo = sourceMembers.Dequeue() as PropertyInfo;
            srcParentType = srcParentPropertyInfo.PropertyType;
            srcParentObj = srcParentPropertyInfo.GetValue(srcParentObj);
    
            // the source parent is not defined, so we can skip this mapping
            if (srcParentObj == null)
                return false;
        }
    
        var srcMemberSpecifiedPropName = propertyMap.SourceMember.Name + "Specified";
        var srcMemberSpecifiedProp = srcParentType.GetProperty(srcMemberSpecifiedPropName);
    
        // if there is no *Specified property, then assume value is specified
        return srcMemberSpecifiedProp == null || (bool)srcMemberSpecifiedProp.GetValue(srcParentObj);
    }
    
    private bool IsNullableType(Type type) => IsGenericType(type, typeof(Nullable<>));
    
    private bool IsGenericType(Type type, Type genericType) => IsGenericType(type) && type.GetGenericTypeDefinition() == genericType;
    
    private bool IsGenericType(Type type) => type.GetTypeInfo().IsGenericType;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-06
      相关资源
      最近更新 更多