我遇到这个问题是因为我需要参加这样的课程:
public class PropertyChange
{
[JsonProperty("name")]
public string PropertyName { get; set; }
[JsonProperty("value")]
public string PropertyValue { get; set; }
[JsonProperty("arrayValue")]
public dynamic[] PropertyArray { get; set; }
}
并将对象的 PropertyArray 属性(使用 Newtonsoft 库从 JSON 反序列化)转换为特定类型的对象数组,其中类型可以从 PropertyName 派生。
我编写了这个名为 DynamicCast<> 的帮助程序类,并决定将其发布在此处,以防其他人遇到与我相同的情况。
这个帮助类允许你编写如下代码:
public class MyType
{
public string A { get; set; }
}
var myCast = new DynamicCast<MyType>();
dynamic dyn = ExpandoObject();
dyn.A = "Hello";
var myType = myCast.Cast(dyn);
Console.WriteLine(myType.A); // prints 'Hello'
这是我如何使用它来解决反序列化问题的示例:
public class JsonTest
{
[JsonProperty("theArray")]
public dynamic[] TheArray { get; set; }
}
var json = "{'theArray':[{'a':'First'},{'a':'Second'}]}";
var jsonTest = JsonConvert.DeserializeObject<JsonTest>(json);
var myCast = new DynamicCast<MyType>();
var myTypes = myCast.Cast(jsonTest.TheArray).ToArray();
Console.WriteLine(myTypes[0].A); // prints 'First'
根据此处的其他答案编写了DynamicCast 类。它看起来像这样:
public class DynamicCast<T> where T: class, new()
{
private Property[] _proprties;
public DynamicCast()
{
_proprties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(x => x.GetSetMethod() != null)
.Where(x => x.GetGetMethod() != null)
.Select(p =>
{
var property = new Property
{
PropertyInfo = p,
Name = p.Name
};
foreach (var attribute in p.GetCustomAttributes(false))
{
if (attribute.GetType() == typeof(JsonPropertyAttribute))
{
var jsonProperty = (JsonPropertyAttribute)attribute;
property.Name = jsonProperty.PropertyName;
break;
}
if (attribute.GetType() == typeof(JsonIgnoreAttribute))
{
return null;
}
}
return property;
})
.Where(p => p != null)
.ToArray();
}
public T Cast(IDictionary<string, object> d)
{
var t = new T();
Fill(d, t);
return t;
}
public T Cast(JObject d)
{
var t = new T();
Fill(d, t);
return t;
}
public dynamic Cast(T t)
{
dynamic d = new ExpandoObject();
Fill(t, d);
return d;
}
public IEnumerable<T> Cast(IEnumerable<JObject> da)
{
return da.Select(e => Cast(e));
}
public IEnumerable<T> Cast(IEnumerable<object> da)
{
return da.Select(e =>
{
if (e is JObject) return Cast((JObject)e);
if (e is IDictionary<string, object>) return Cast((IDictionary<string, object>)e);
return null;
});
}
public void Fill(IDictionary<string, object> values, T target)
{
foreach (var property in _proprties)
if (values.TryGetValue(property.Name, out var value))
property.PropertyInfo.SetValue(target, value, null);
}
public void Fill(JObject values, T target)
{
foreach (var property in _proprties)
{
if (values.TryGetValue(property.Name, out var value))
{
if (value is JValue jvalue)
{
var propertyValue = Convert.ChangeType(jvalue.Value, property.PropertyInfo.PropertyType);
property.PropertyInfo.SetValue(target, propertyValue, null);
}
}
}
}
public void Fill(T obj, IDictionary<string, object> target)
{
foreach (var property in _proprties)
target[property.Name] = property.PropertyInfo.GetValue(obj, null);
}
private class Property
{
public PropertyInfo PropertyInfo;
public string Name;
}
}
您可以在 .Net Fiddle 中亲自尝试一下:https://dotnetfiddle.net/J1JXgU