2012-03-26 68 views
1

我正在使用Value Injector来管理ASP.NET MVC项目中的映射,迄今为止它一直很棒。该域具有长度度量的概念,在数据库中存储为标准度量单位,并以小数值形式显示到服务层。如何使用Value Injector检查目标属性的属性?

在UI上下文特定的情况下呈现长度,具体取决于作为度量的对象,用户区域等。关于由视图模型类型的属性上的属性表示的上下文提示。使用值注入器,我想在注入时检查这些属性,并显示一个适当格式的字符串来显示,当源属性是一个小数,目标属性是用上述属性之一装饰的字符串。

namespace TargetValueAttributes 
{ 
    public class Person 
    { 
     public decimal Height { get; set; } 
     public decimal Waist { get; set; } 
    } 

    public class PersonViewModel 
    { 
     [LengthLocalizationHint(LengthType.ImperialFeetAndInches)] 
     [LengthLocalizationHint(LengthType.MetricMeters)] 
     public string Height { get; set; } 

     [LengthLocalizationHint(LengthType.ImperialInches)] 
     [LengthLocalizationHint(LengthType.MetricCentimeters)] 
     public string Waist { get; set; } 
    } 

    public enum LengthType 
    { 
     MetricMeters, 
     MetricCentimeters, 
     ImperialFeetAndInches, 
     ImperialInches 
    } 

    [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] 
    public class LengthLocalizationHintAttribute : Attribute 
    { 
     public LengthType SuggestedLengthType { get; set; } 

     public LengthLocalizationHintAttribute(LengthType suggestedLengthType) 
     { 
      SuggestedLengthType = suggestedLengthType; 
     } 
    } 

    public class LengthLocalizationInjection : FlatLoopValueInjection<decimal, string> 
    { 
     protected override void Inject(object source, object target) 
     { 
      base.Inject(source, target);//I want to be able to inspect the attributes on the target value here 
     } 
     protected override string SetValue(decimal sourceValues) 
     { 
      var derivedLengthType = LengthType.MetricMeters;//here would be even better 
      return sourceValues.ToLength(derivedLengthType);//this is an extension method that does the conversion to whatever the user needs to see 
     } 
    } 

回答

1

在源代码中寻找后,我想出了一个基于`FlatLoopValueInjection'实现的解决方案。

public abstract class LocalizationStringInjection<TSource, TTarget> : LoopValueInjectionBase 
{ 
    public ILocalizationContext LocalizationContext { get; set; } 

    protected LocalizationStringInjection(ILocalizationContext localizationContext) 
    { 
     LocalizationContext = localizationContext; 
    } 

    protected virtual bool TypesMatch(Type sourceType, Type targetType) 
    { 
     return sourceType == typeof(TSource) && targetType == typeof(TTarget); 
    } 

    protected override void Inject(object source, object target) 
    { 
     foreach (PropertyDescriptor targetPropertyDescriptor in target.GetProps()) 
     { 
      var t1 = targetPropertyDescriptor; 
      var es = UberFlatter.Flat(targetPropertyDescriptor.Name, source, type => TypesMatch(type, t1.PropertyType)); 

      var endpoint = es.FirstOrDefault(); 
      if (endpoint == null) continue; 

      var sourceValue = endpoint.Property.GetValue(endpoint.Component) is TSource ? (TSource)endpoint.Property.GetValue(endpoint.Component) : default(TSource); 

      if (AllowSetValue(sourceValue)) 
       targetPropertyDescriptor.SetValue(target, SetValue(sourceValue, targetPropertyDescriptor)); 
     } 
    } 

    protected abstract TTarget SetValue(TSource sourcePropertyValue, PropertyDescriptor targetPropertyDescriptor); 
} 

public class LengthLocalizationStringInjection : LocalizationStringInjection<decimal, string> 
{ 
    public LengthLocalizationStringInjection(ILocalizationContext localizationContext) : base(localizationContext) { } 

    protected override string SetValue(decimal sourceValue, PropertyDescriptor targetPropertyDescriptor) 
    { 
     var lengthHints = targetPropertyDescriptor.Attributes.Cast<object>().Where(attribute => attribute.GetType() == typeof(LengthLocalizationAttribute)).Cast<LengthLocalizationAttribute>().ToList(); 
     return lengthHints.Any() ? sourceValue.ToLength(lengthHints.First(l => l.SuggestedLengthType == LocalizationContext.Length).SuggestedLengthType) : sourceValue.ToLength(default(LengthType)); 
    } 
} 

这已经证明足够我现在的目的。我省略了一些引用类型,以免模糊这个想法。