Как я могу проверить атрибуты целевого свойства с помощью Value Injector? - PullRequest
1 голос
/ 26 марта 2012

Я использую Value Injector для управления моими сопоставлениями в проекте ASP.NET MVC, и до сих пор это было здорово.Домен имеет концепцию измерения длины, которая хранится в виде стандартных метрических единиц в дБ и отображается в виде десятичного значения вплоть до уровня обслуживания.

Отображение длин в контексте пользовательского интерфейса в зависимости от измеряемого объекта, пользовательская культура и т. д. Советы по контексту, обозначаемому атрибутами в свойствах типов моделей представлений.Используя Value Injector, я хочу проверить эти атрибуты во время внедрения и показать строку соответствующего формата для отображения, когда свойство source является десятичным, а свойство target является строкой, украшенной одним из вышеуказанных атрибутов.

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 Ответ

1 голос
/ 26 марта 2012

После поиска источника я нашел решение, основанное на реализации 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));
    }
}

Пока это оказалось достаточно для моих целей. Я пропустил некоторые ссылочные типы, чтобы не затенять идею.

...