Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 当属性类型包括泛型类型时,如何将泛型JsonConverter应用于泛型类的属性?_C#_.net Core_Json.net - Fatal编程技术网

C# 当属性类型包括泛型类型时,如何将泛型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

我对Json.NET有一个问题。当属性类型包括类本身的泛型类型参数时,我需要为一个泛型类中的不同属性使用不同的泛型JSONConverter

让我们使用以下泛型类,其中一些需要转换的属性使用参数
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编译器时间错误您不能在属性中使用泛型参数,请参阅。实际类型作为参数传递给and
WriteJson()
,因此您需要使转换器非通用,并通过其中的反射完成所有操作。或者,您可以使用自定义契约解析器应用转换器。你能和我共用一个房间吗?
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;
}