如何使用Value Injector检查目标属性的属性
本文关键字:属性 目标 检查 Injector 何使用 Value | 更新日期: 2023-09-27 18:28:57
我正在使用Value Injector来管理ASP.NET MVC项目中的映射,到目前为止效果非常好。该域具有长度测量的概念,长度测量以标准度量单位存储在数据库中,并以十进制值的形式向服务层公开。
UI上下文中特定长度的呈现,具体取决于要测量的对象、用户区域性等。有关视图模型类型属性上的属性表示的上下文的提示。使用Value Injector,我希望在注入时检查这些属性,并在源属性是十进制而目标属性是用上述属性之一装饰的字符串时显示一个格式适当的字符串。
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
}
}
在深入研究源代码后,我提出了一个基于"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));
}
}
事实证明,这对我目前的目的来说已经足够好了。我省略了一些引用的类型,以免混淆这个想法。