Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System.Text.Json: The type 'System.String&' may not be used as a type argument. #80816

Closed
ErrorEater opened this issue Jan 18, 2023 · 6 comments

Comments

@ErrorEater
Copy link

Why the following serialization fails when the parameter is a reference type?

public class JsonRpcRequest
{
    public JsonRpcRequest(in string method)
    {
        Method = method;
    }
}

var request = new JsonRpcRequest("method1");
var content = JsonSerializer.SerializeToElement(request);
System.ArgumentException
  HResult=0x80070057
  Message=The type 'System.String&' may not be used as a type argument.
  Source=System.Private.CoreLib
  StackTrace:
   at System.RuntimeType.ThrowIfTypeNeverValidGenericArgument(RuntimeType type)
   at System.RuntimeType.SanityCheckGenericArguments(RuntimeType[] genericArguments, RuntimeType[] genericParameters)
   at System.RuntimeType.MakeGenericType(Type[] instantiation)
   at System.Text.Json.Serialization.Converters.ObjectConverterFactory.CreateConverter(Type typeToConvert, JsonSerializerOptions options)
   at System.Text.Json.Serialization.JsonConverterFactory.GetConverterInternal(Type typeToConvert, JsonSerializerOptions options)
   at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.GetConverterForType(Type typeToConvert, JsonSerializerOptions options, Boolean resolveJsonConverterAttribute)
   at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.CreateJsonTypeInfo(Type type, JsonSerializerOptions options)
   at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.GetTypeInfo(Type type, JsonSerializerOptions options)
   at System.Text.Json.JsonSerializerOptions.GetTypeInfoNoCaching(Type type)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at System.Text.Json.JsonSerializerOptions.GetTypeInfoInternal(Type type, Boolean ensureConfigured, Boolean resolveIfMutable)
   at System.Text.Json.JsonSerializer.GetTypeInfo(JsonSerializerOptions options, Type inputType)
   at System.Text.Json.JsonSerializer.GetTypeInfo[T](JsonSerializerOptions options)
   at System.Text.Json.JsonSerializer.SerializeToElement[TValue](TValue value, JsonSerializerOptions options)

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Jan 18, 2023
@ghost
Copy link

ghost commented Jan 18, 2023

Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis
See info in area-owners.md if you want to be subscribed.

Issue Details

Why the following serialization fails when the parameter is a reference type?

public class JsonRpcRequest
{
    public JsonRpcRequest(in string method)
    {
        Method = method;
    }
}

var request = new JsonRpcRequest("method1");
var content = JsonSerializer.SerializeToElement(request);
System.ArgumentException
  HResult=0x80070057
  Message=The type 'System.String&' may not be used as a type argument.
  Source=System.Private.CoreLib
  StackTrace:
   at System.RuntimeType.ThrowIfTypeNeverValidGenericArgument(RuntimeType type)
   at System.RuntimeType.SanityCheckGenericArguments(RuntimeType[] genericArguments, RuntimeType[] genericParameters)
   at System.RuntimeType.MakeGenericType(Type[] instantiation)
   at System.Text.Json.Serialization.Converters.ObjectConverterFactory.CreateConverter(Type typeToConvert, JsonSerializerOptions options)
   at System.Text.Json.Serialization.JsonConverterFactory.GetConverterInternal(Type typeToConvert, JsonSerializerOptions options)
   at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.GetConverterForType(Type typeToConvert, JsonSerializerOptions options, Boolean resolveJsonConverterAttribute)
   at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.CreateJsonTypeInfo(Type type, JsonSerializerOptions options)
   at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.GetTypeInfo(Type type, JsonSerializerOptions options)
   at System.Text.Json.JsonSerializerOptions.GetTypeInfoNoCaching(Type type)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at System.Text.Json.JsonSerializerOptions.GetTypeInfoInternal(Type type, Boolean ensureConfigured, Boolean resolveIfMutable)
   at System.Text.Json.JsonSerializer.GetTypeInfo(JsonSerializerOptions options, Type inputType)
   at System.Text.Json.JsonSerializer.GetTypeInfo[T](JsonSerializerOptions options)
   at System.Text.Json.JsonSerializer.SerializeToElement[TValue](TValue value, JsonSerializerOptions options)

Author: aliveli186
Assignees: -
Labels:

area-System.Text.Json, untriaged

Milestone: -

@Tornhoof
Copy link
Contributor

Why do you use "in string" instead of "string"?

@eiriktsarpalis
Copy link
Member

Duplicate of #46088.

@ghost ghost removed the untriaged New issue has not been triaged by the area owner label Jan 19, 2023
@ErrorEater
Copy link
Author

Why do you use "in string" instead of "string"?

@Tornhoof To prevent creating another copy of the string. GC, performance things.

@Tornhoof
Copy link
Contributor

Yeah, but Strings are both reference types and immutable, so that's the default behavior.

@ErrorEater
Copy link
Author

Yeah, but Strings are both reference types and immutable, so that's the default behavior.

I benchmarked both methods in Release mode and the result are below. The difference is insignificant.

// * Summary *

BenchmarkDotNet=v0.13.3, OS=Windows 11 (10.0.22621.1105)
AMD Ryzen 5 4600H with Radeon Graphics, 1 CPU, 12 logical and 6 physical cores
.NET SDK=7.0.100
  [Host]     : .NET 7.0.0 (7.0.22.51805), X64 RyuJIT AVX2
  DefaultJob : .NET 7.0.0 (7.0.22.51805), X64 RyuJIT AVX2


|   Method |     Mean |     Error |    StdDev | Ratio | RatioSD |    Gen0 | Allocated | Alloc Ratio |
|--------- |---------:|----------:|----------:|------:|--------:|--------:|----------:|------------:|
| RunByVal | 3.638 us | 0.0718 us | 0.1367 us |  1.00 |    0.00 | 11.4746 |  23.44 KB |        1.00 |
| RunByRef | 3.506 us | 0.0580 us | 0.0514 us |  0.96 |    0.04 | 11.4746 |  23.44 KB |        1.00 |

// * Hints *
Outliers
  StringParamTester.RunByVal: Default -> 2 outliers were removed (4.10 us, 4.12 us)
  StringParamTester.RunByRef: Default -> 3 outliers were removed (3.68 us..4.79 us)

// * Legends *
  Mean        : Arithmetic mean of all measurements
  Error       : Half of 99.9% confidence interval
  StdDev      : Standard deviation of all measurements
  Ratio       : Mean of the ratio distribution ([Current]/[Baseline])
  RatioSD     : Standard deviation of the ratio distribution ([Current]/[Baseline])
  Gen0        : GC Generation 0 collects per 1000 operations
  Allocated   : Allocated memory per single operation (managed only, inclusive, 1KB = 1024B)
  Alloc Ratio : Allocated memory ratio distribution ([Current]/[Baseline])
  1 us        : 1 Microsecond (0.000001 sec)

// * Diagnostic Output - MemoryDiagnoser *


// ***** BenchmarkRunner: End *****
Run time: 00:01:21 (81.49 sec), executed benchmarks: 2

Global total time: 00:01:26 (86.84 sec), executed benchmarks: 2
// * Artifacts cleanup *


internal class Program
{
    private static void Main(string[] args)
    {
        var summary = BenchmarkRunner.Run<StringParamTester>();
    }
}

[MemoryDiagnoser]
public class StringParamTester
{
    private string _text = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.";

    [Benchmark(Baseline = true)]
    public void RunByVal()
    {
        var count = 0;

        for (var i = 0; i < 1000; i++)
        {
            var r = new JsonRpcRequestVal(_text);
            count += r.Method.Length;
        }

        var temp = ++count;
    }

    [Benchmark]
    public void RunByRef()
    {
        var count = 0;

        for (var i = 0; i < 1000; i++)
        {
            var r = new JsonRpcRequestRef(_text);
            count += r.Method.Length;
        }

        var temp = ++count;
    }
}

public class JsonRpcRequestVal
{
    public JsonRpcRequestVal(string method)
    {
        Method = method;
    }

    public string Method { get; set; }
}

public class JsonRpcRequestRef
{
    public JsonRpcRequestRef(in string method)
    {
        Method = method;
    }

    public string Method { get; set; }
}

@ghost ghost locked as resolved and limited conversation to collaborators Feb 19, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants