决定使用 Mapster 而不是自己编写转换/映射方法。在他们的 github wiki 上还没有找到任何可以满足我的用例的东西。
我有一个 Dictionary
这里有一个目标类型的例子:
public sealed class TriggerSettings
{
public bool ShouldRun { get; set; }
public SimpleTriggerRecurringType RecurringType { get; set; } // enum
public SimpleTriggerDayOfWeek DayOfWeek { get; set; } // enum
public int Hour { get; set; }
public int Minute { get; set; }
public int Second { get; set; }
}
字典中的键可能不正确,键集可能不包含所有目标属性名称。我想根据目标类型的属性获取所有有效的属性名称和映射字符串表示,但条件是我已经拥有目标类型实例并且不想更改字典中不存在的属性。
是否有一种简单的方法可以使用 TypeAdapterConfig 创建一次这样的配置,或者它只能在运行时为特定的字典实例解析?
之前我用我自己的简单方法,使用反射,看起来像这样
public static void ConvertAndMapKeyValuePairsOnObject<T>(T obj, IDictionary<string, string> propertyNameValuePairs)
{
var properties = typeof(T).GetProperties(
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance);
foreach (var property in properties)
{
if (!propertyNameValuePairs.ContainsKey(property.Name))
{
continue;
}
var converter = TypeDescriptor.GetConverter(property.PropertyType);
var result = converter.ConvertFrom(propertyNameValuePairs[property.Name]);
if (result is null)
{
continue;
}
property.SetValue(obj, result);
}
}
找到了一个简单的解决方案。不确定它是否是最好的,但在这种情况下,
UseDestinationValue
方法可以用在带有谓词的 TypeAdapterSetter
对象上。将忽略所有无效的属性名称,以及不在字典键集中的目标对象属性。
这里有一个扩展方法,可以在你打算用字典的内容映射到的对象上调用。
public static class MapsterExtensions
{
public static TDestination UpdateWithDictionary<TDestination>(
this TDestination source,
IDictionary<string, string> propertyNameValuePairs)
{
var mappingConfig = new TypeAdapterConfig()
.NewConfig<IDictionary<string, string>, TDestination>()
.UseDestinationValue(member => !propertyNameValuePairs.ContainsKey(member.Name));
return propertyNameValuePairs.Adapt(source, mappingConfig.Config);
}
}
用法示例:
var propertyDictionary = new Dictionary<string, string>
{
{
"Hour", "12"
},
{
"Minute", "30"
}
};
var settings = new TriggerSettings
{
ShouldRun = true
};
Console.WriteLine($"Hour property before mapping: {settings.Hour}");
Console.WriteLine($"Minute property before mapping: {settings.Minute}");
Console.WriteLine($"ShouldRun property before mapping: {settings.ShouldRun}");
settings.UpdateWithDictionary(propertyDictionary);
Console.WriteLine($"Hour property after mapping: {settings.Hour}");
Console.WriteLine($"Minute property after mapping: {settings.Minute}");
Console.WriteLine($"ShouldRun property after mapping (should remain the same): {settings.ShouldRun}");
输出:
Hour property before mapping: 0
Minute property before mapping: 0
ShouldRun property before mapping: True
Hour property after mapping: 12
Minute property after mapping: 30
ShouldRun property after mapping (should remain the same): True