C# 通用对象更新程序-将数组转换为列表
我试图创建一个泛型类,它能够更新对象的任何属性 我使它适用于几种情况,例如单值属性int、string、bool等。。如果属性是IEnumerable,它也可以很好地工作,在这种情况下,列表或数组都可以正常工作 但是我遇到了一个场景,如果属性是List,但要指定的值是数组,或者相反。在标准情况下,我可以简单地使用ToList或ToArray,但在一般情况下,我不知道如何使用ToList或ToArray 这是密码C# 通用对象更新程序-将数组转换为列表,c#,generics,C#,Generics,我试图创建一个泛型类,它能够更新对象的任何属性 我使它适用于几种情况,例如单值属性int、string、bool等。。如果属性是IEnumerable,它也可以很好地工作,在这种情况下,列表或数组都可以正常工作 但是我遇到了一个场景,如果属性是List,但要指定的值是数组,或者相反。在标准情况下,我可以简单地使用ToList或ToArray,但在一般情况下,我不知道如何使用ToList或ToArray 这是密码 public static class ObjectUpdater { pu
public static class ObjectUpdater
{
public static T Patch<T>(T obj, IEnumerable<KeyValuePair<string, object>> delta)
{
if (obj == null || delta == null)
{
return obj;
}
foreach (var deltaItem in delta)
{
Patch(obj, deltaItem.Key, deltaItem.Value);
}
return obj;
}
private static void Patch<T>(T obj, string propertyName, object value)
{
var propertyInfo = obj.GetType().GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
if (propertyInfo == null || !propertyInfo.CanRead || !propertyInfo.CanWrite)
{
throw new ArgumentException($"Property '{propertyName}' doesn't exist or cannot be updated");
}
SetPropertyValue(obj, value, propertyInfo);
}
private static void SetPropertyValue(object obj, object value, PropertyInfo propertyInfo)
{
if (propertyInfo.PropertyType.IsEnum)
{
propertyInfo.SetValue(obj, Convert.ToInt32(value));
return;
}
// property parsing is based on the target property's TryParse() method
// big / small enough float / DateTime values had issues, as the ToString() might lose precision >> they're handled separately
if (value is float)
{
SetPropertyValueAsFloat(obj, (float)value, propertyInfo);
return;
}
if (value is DateTime)
{
SetPropertyValueAsDateTime(obj, (DateTime)value, propertyInfo);
return;
}
var systemType = propertyInfo.PropertyType.UnderlyingSystemType;
var tryParse = systemType.GetMethod("TryParse", new[] {typeof(string), systemType.MakeByRefType()});
if (tryParse == null)
{
propertyInfo.SetValue(obj, value);
return;
}
var parameters = new object[]
{
value.ToString(),
null
};
var canParse = (bool) tryParse.Invoke(null, parameters);
propertyInfo.SetValue(obj, canParse ? parameters[1] : value);
}
private static void SetPropertyValueAsDateTime(object obj, DateTime value, PropertyInfo propertyInfo)
{
// code to handle DateTime value
}
}
// and two test methods
[Fact]
private void Patch_StringListPropertyFromArrayValue()
{
var sourceObject = new TestClassWithCollectionProperties
{
StringListProperty = null
};
var expectedResult = new TestClassWithCollectionProperties
{
StringListProperty = new List<string>
{
"abc",
"def"
}
};
var delta = new List<KeyValuePair<string, object>>
{
new KeyValuePair<string, object>("StringListProperty",
new []
{
"abc",
"def"
})
};
var result = ObjectUpdater.Patch(sourceObject, delta);
result.ShouldBeEquivalentTo(expectedResult);
}
[Fact]
private void Patch_StringArrayPropertyFromListValue()
{
var sourceObject = new TestClassWithCollectionProperties
{
StringArrayProperty = null
};
var expectedResult = new TestClassWithCollectionProperties
{
StringArrayProperty = new[]
{
"abc",
"def"
}
};
var delta = new List<KeyValuePair<string, object>>
{
new KeyValuePair<string, object>("StringArrayProperty",
new List<string>
{
"abc",
"def"
})
};
var result = ObjectUpdater.Patch(sourceObject, delta);
result.ShouldBeEquivalentTo(expectedResult);
}
但是由于ObjectUpdater.Patch抛出System.ArgumentException并显示以下消息,此测试失败
“System.String[]”类型的对象无法转换为“System.Collections.Generic.List`1[System.String]”类型
有什么建议吗?好吧,在tryParse尝试之前,您可以在代码中的某个地方处理具体情况,如下所示:
if (value != null && value.GetType() != propertyInfo.PropertyType
// from T[]
&& value.GetType().IsArray && value.GetType().GetArrayRank() == 1
// to List<T>
&& propertyInfo.PropertyType.IsGenericType
&& propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(List<>)
&& propertyInfo.PropertyType.GetGenericArguments()[0] == value.GetType().GetElementType())
{
var T = value.GetType().GetElementType();
var listT = typeof(List<>).MakeGenericType(T);
// new List<T>(IEnumerable<T> items)
var enumerableT = typeof(IEnumerable<>).MakeGenericType(T);
var newListT = listT.GetConstructor(new Type [] { enumerableT });
var list = newListT.Invoke(new[] { value });
propertyInfo.SetValue(obj, list);
return;
}
隐马尔可夫模型。。您可以尝试使用将列表转换为数组。要阵列您的东西,并将其转换回循环中的列表?是的,它确实可以处理数组>>列表的情况。您是否也可以提供列表>>阵列方案的版本?当然可以。您只需要通过反射检测case和call List.ToArray方法。但请注意,您正在进入一个无休止的循环:不管怎样,就是这样。
if (value != null && value.GetType() != propertyInfo.PropertyType
// to T[]
&& propertyInfo.PropertyType.IsArray && propertyInfo.PropertyType.GetArrayRank() == 1
// from List<T>
&& value.GetType().IsGenericType
&& value.GetType().GetGenericTypeDefinition() == typeof(List<>)
&& value.GetType().GetGenericArguments()[0] == propertyInfo.PropertyType.GetElementType())
{
// List<T>.ToArray()
var toArray = value.GetType().GetMethod("ToArray", Type.EmptyTypes);
var array = toArray.Invoke(value, null);
propertyInfo.SetValue(obj, array);
return;
}