Table of Contents

NBMsgPack051: Prefer modern .NET APIs

Some APIs exist to support targeting .NET Standard or .NET Framework, while other APIs are available when targeting .NET that offer superior performance and reliability. This diagnostic is reported when code uses the lesser API while the preferred API is available.

The diagnostic message will direct you to the preferred API.

In multi-targeting projects where switching to the preferred API is inadvisable because it would break the build for older target frameworks or require the use of #if sections, you may suppress this warning.

Example violation

The following code constructs a union type mapping. This method may fail at runtime if the type arguments are not attributed with GenerateShapeAttribute.

[GenerateShape]
partial class MyType { }

[GenerateShape]
partial class MyDerivedType : MyType { }

[GenerateShapeFor<MyType>]
partial class Witness;

class Foo
{
    internal DerivedShapeMapping<MyType> ConstructUnionMapping()
    {
        DerivedShapeMapping<MyType> mapping = new();
        mapping.AddSourceGenerated<MyDerivedType>(1);
        return mapping;
    }
}

This is acceptable for projects that target .NET Standard or .NET Framework because compile-time enforcement is not available. But if the project targets .NET a warning will be emitted to encourage use of the safer APIs.

Resolution

Per the message in the warning, switch to the overload that takes a type that is constrained to guaranteeing availability of its shape:

[GenerateShape]
partial class MyType { }

[GenerateShape]
partial class MyDerivedType : MyType { }

[GenerateShapeFor<MyType>]
partial class Witness;

class Foo
{
    internal DerivedShapeMapping<MyType> ConstructUnionMapping()
    {
        DerivedShapeMapping<MyType> mapping = new();
        mapping.Add<MyDerivedType>(1);
        return mapping;
    }
}

Or in a multitargeting project, use the preferred API only where it's available:

        [GenerateShape]
        partial class MyType { }

        [GenerateShape]
        partial class MyDerivedType : MyType { }

        [GenerateShapeFor<MyType>]
        partial class Witness;

        class Foo
        {
            internal DerivedShapeMapping<MyType> ConstructUnionMapping()
            {
                DerivedShapeMapping<MyType> mapping = new();
#if NET
                mapping.Add<MyDerivedType>(1);
#else
                mapping.AddSourceGenerated<MyDerivedType>(1);
#endif
                return mapping;
            }
        }
Tip

In a multi-targeting project, simply reducing the severity of the diagnostic from Warning to something lesser may be a better option than creating #if/#else/#endif regions in many places.