C# 当属性类型包括泛型类型时,如何将泛型JsonConverter应用于泛型类的属性?
我对Json.NET有一个问题。当属性类型包括类本身的泛型类型参数时,我需要为一个泛型类中的不同属性使用不同的泛型JSONConverter 让我们使用以下泛型类,其中一些需要转换的属性使用参数C# 当属性类型包括泛型类型时,如何将泛型JsonConverter应用于泛型类的属性?,c#,.net-core,json.net,C#,.net Core,Json.net,我对Json.NET有一个问题。当属性类型包括类本身的泛型类型参数时,我需要为一个泛型类中的不同属性使用不同的泛型JSONConverter 让我们使用以下泛型类,其中一些需要转换的属性使用参数TTable: public class ExpresssionDTO<TTable> : BaseDTO where TTable : class { [JsonProperty(ItemConverterType = typeof(PredicateSerializationCon
TTable
:
public class ExpresssionDTO<TTable> : BaseDTO where TTable : class
{
[JsonProperty(ItemConverterType = typeof(PredicateSerializationConverter<>))]
public ICollection<Expression<Func<TTable, bool>>> Predicates { get; set; } = new List<Expression<Func<TTable, bool>>>();
[JsonConverter(converterType: typeof(FilterSerializationConverter<>))]
public Expression<Func<TTable, object>> Filter { get; set; } = null;
}
对于DefaultContractResolver
,也会出现此问题
有什么方法可以解决我的问题吗?您要做的是使用泛型参数
TTable
作为自定义JSON转换器的泛型参数,如下所示:
public class ExpresssionDTO<TTable> : BaseDTO where TTable : class
{
[JsonProperty(ItemConverterType = typeof(PredicateSerializationConverter<TTable>))] // Here
public ICollection<Expression<Func<TTable, bool>>> Predicates { get; set; } = new List<Expression<Func<TTable, bool>>>();
[JsonConverter(converterType: typeof(FilterSerializationConverter<TTable>))] // And here
public Expression<Func<TTable, object>> Filter { get; set; } = null;
}
然后将其应用于模型,如下所示,将打开的泛型转换器类型作为转换器参数传递:
public class ExpresssionDTO<TTable> : BaseDTO where TTable : class
{
[JsonProperty(ItemConverterType = typeof(GenericFuncExpressionArgumentConverterDecorator), ItemConverterParameters = new object [] { typeof(PredicateSerializationConverter<>) })]
public ICollection<Expression<Func<TTable, bool>>> Predicates { get; set; } = new List<Expression<Func<TTable, bool>>>();
[JsonConverter(typeof(GenericFuncExpressionArgumentConverterDecorator), new object [] { typeof(FilterSerializationConverter<>) })]
public Expression<Func<TTable, object>> Filter { get; set; } = null;
}
public class expressiondto:BaseDTO其中TTable:class
{
[JsonProperty(ItemConverterType=typeof(GenericFunctionExpressionArgumentConverterDecorator),ItemConverterParameters=new object[]{typeof(PredicateSerializationConverter)}]
公共ICollection谓词{get;set;}=new List();
[JsonConverter(typeof(GenericFunctionExpressionArgumentConverterDecorator),新对象[]{typeof(FilterSerializationConverter)}]
公共表达式筛选器{get;set;}=null;
}
演示小提琴。将属性的类型放入空的
@Charlieface中,该属性也不起作用-如果我尝试将泛型类型传递到括号中,则会出现编译器时间错误。PredicateSerializationConverter
这会产生什么错误?@Charlieface编译器时间错误您不能在属性中使用泛型参数,请参阅。实际类型作为参数传递给andWriteJson()
,因此您需要使转换器非通用,并通过其中的反射完成所有操作。或者,您可以使用自定义契约解析器应用转换器。你能和我共用一个房间吗?
public class ExpresssionDTO<TTable> : BaseDTO where TTable : class
{
[JsonProperty(ItemConverterType = typeof(PredicateSerializationConverter<TTable>))] // Here
public ICollection<Expression<Func<TTable, bool>>> Predicates { get; set; } = new List<Expression<Func<TTable, bool>>>();
[JsonConverter(converterType: typeof(FilterSerializationConverter<TTable>))] // And here
public Expression<Func<TTable, object>> Filter { get; set; } = null;
}
public class GenericFuncExpressionArgumentConverterDecorator : JsonConverter
{
readonly Type openGenericConverterType;
volatile Tuple<Type, JsonConverter> converterCache;
public GenericFuncExpressionArgumentConverterDecorator(Type openGenericConverterType)
{
if (openGenericConverterType == null)
throw new ArgumentNullException();
if (!openGenericConverterType.IsSubclassOf(typeof(JsonConverter)))
throw new ArgumentException(string.Format("{0} is not a JsonConvreter", GetType().Name));
if (!openGenericConverterType.IsGenericTypeDefinition)
throw new ArgumentException(string.Format("{0} is not an open generic type", GetType().Name));
this.openGenericConverterType = openGenericConverterType;
}
public override bool CanConvert(Type objectType) =>
throw new NotImplementedException(string.Format("{0} is intended to be applied via a JsonConverter or JsonProperty attribute", GetType().Name));
JsonConverter GetConverter(Type objectType)
{
var cache = converterCache;
if (cache != null && cache.Item1 == objectType)
return cache.Item2;
// Despite the documentation, Expression<T> is not actually sealed in .Net 5!
// https://github.com/dotnet/runtime/blob/master/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/LambdaExpression.cs#L174
var expressionType = objectType.BaseTypesAndSelf().Where(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Expression<>)).FirstOrDefault();
if (expressionType == null)
throw new JsonSerializationException(string.Format("Invalid expression type {0}", objectType));
var delegateType = objectType.GetGenericArguments().Single();
if (!delegateType.IsGenericType || delegateType.GetGenericTypeDefinition() != typeof(Func<,>))
throw new JsonSerializationException(string.Format("Invalid delegate type {0}", delegateType));
var argType = delegateType.GetGenericArguments()[0];
var converterType = openGenericConverterType.MakeGenericType(new [] { argType });
var converter = (JsonConverter)Activator.CreateInstance(converterType);
converterCache = Tuple.Create(objectType, converter);
return converter;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) =>
GetConverter(objectType).ReadJson(reader, objectType, existingValue, serializer);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) =>
GetConverter(value.GetType()).WriteJson(writer, value, serializer);
}
public static class TypeExtensions
{
public static IEnumerable<Type> BaseTypesAndSelf(this Type type)
{
while (type != null)
{
yield return type;
type = type.BaseType;
}
}
}
public class ExpresssionDTO<TTable> : BaseDTO where TTable : class
{
[JsonProperty(ItemConverterType = typeof(GenericFuncExpressionArgumentConverterDecorator), ItemConverterParameters = new object [] { typeof(PredicateSerializationConverter<>) })]
public ICollection<Expression<Func<TTable, bool>>> Predicates { get; set; } = new List<Expression<Func<TTable, bool>>>();
[JsonConverter(typeof(GenericFuncExpressionArgumentConverterDecorator), new object [] { typeof(FilterSerializationConverter<>) })]
public Expression<Func<TTable, object>> Filter { get; set; } = null;
}