2012-03-26 70 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)); 
    } 
} 

這已經證明足夠我現在的目的。我省略了一些引用類型,以免模糊這個想法。