Search code examples
c#.net-6.0.net-7.0c#-11.0.net-generic-math

Adding operator support to interfaces (Preview Feature in .NET 6)


Just a warning, this question requires a preview of .NET 6 to be installed


I'm trying to create an interface in C# that can allow the + operator similar to how it is implemented in Microsoft's INumber<T>.

Interfaces.cs

using System;
using System.Runtime.Versioning;

namespace InterfaceTest;

[RequiresPreviewFeatures]
public interface IExtendedArray<T> : IAdditionOperators<IExtendedArray<T>, IExtendedArray<T>, IExtendedArray<T>>
    where T : INumber<T>
{
    Array Data { get; }
}

[RequiresPreviewFeatures]
public interface IExtendedFloatingPointArray<T> : IExtendedArray<T>
    where T : IFloatingPoint<T>
{

}

InterfaceTest.csproj

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <EnablePreviewFeatures>true</EnablePreviewFeatures>
        <TargetFramework>net6.0</TargetFramework>
        <ImplicitUsings>false</ImplicitUsings>
        <Nullable>enable</Nullable>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="System.Runtime.Experimental" Version="6.0.0-preview.7.21377.19" />
    </ItemGroup>

</Project>

However, this code produces

error CS8920: The interface 'InterfaceTest.IExtendedArray' cannot be used as type parameter 'TSelf' in the generic type or method 'IAdditionOperators<TSelf, TOther, TResult>'. The constraint interface 'System.IAdditionOperators<InterfaceTest.IExtendedArray, InterfaceTest.IExtendedArray, InterfaceTest.IExtendedArray>' or its base interface has static abstract members.

Is there a way achieve this with custom types?


dotnet --list-sdks shows I have 6.0.100-rc.1.21458.32 installed. But I just had it installed through the Visual Studio 2022 Preview 4.


Solution

  • Finally I was able to reproduce your issue - needed to install VS 2022 preview (2019 version compiled code just fine but failed in the runtime) or use dotnet build from terminal.

    If you want to do something similar with INumber you need to follow the same pattern with TSelf type reference (if I'm not mistaken it is called curiously recurring template pattern):

    [RequiresPreviewFeatures]
    public interface IExtendedArray<TSelf, T> : IAdditionOperators<TSelf, TSelf, TSelf> where TSelf : IExtendedArray<TSelf, T> where T : INumber<T>
    {
        T[] Data { get; }
    }
    
    
    [RequiresPreviewFeatures]
    public interface IExtendedFloatingPointArray<TSelf, T> : IExtendedArray<TSelf, T>
        where TSelf : IExtendedFloatingPointArray<TSelf, T>
        where T : IFloatingPoint<T>
    {
    
    }