Home > Mobile >  with keyword does not compile when used with generic type
with keyword does not compile when used with generic type

Time:10-18

When using the C# with keyword with an actual struct type it works exactly as expected, however when dealing with some generic type T that is constrained to be a struct it results in a compiler error.

Is this a bug or intended behaviour, and if so, what's stopping the generic approach from working?

public interface ICountSomething
{
    public int Counter { get; }
}

public struct ActualStruct : ICountSomething
{
    public string Name { get; init; }
    public int Counter { get; init; }
}

public class Blah<T>
    where T : struct, ICountSomething
{
    public T DoSomethingWithGenericConstrainedToStruct(T input)
    {
        // Does not compile
        return input with
        {
            Counter = input.Counter   1,
        };
    }

    public ActualStruct DoSomethingWithActualStruct(ActualStruct input)
    {
        // Compiles ok
        return input with
        {
            Counter = input.Counter   1,
        };
    }
}

enter image description here

CodePudding user response:

There are two issues - Counter on the interface is readonly so can't be modified and/or used inside with expression. Change the interface to:

public interface ICountSomething
{
    public int Counter { get; init; }
}

The with itself seems to be Rider/Resharper issue, the code should compile just fine (after adding init to the interface) - checked at sharplab.io. Submitted the bug for Rider.

CodePudding user response:

Since T is a generic type, the compiler does not know which type is going to be used for T. It knows it is a struct, but it cannot tell which properties struct T has.

The with keyword has to know which properties it can set. Since there is no way the compiler can possibly know which properties there are in T, you cannot use with.

You also can't use an interface here because there is not a specific interface for value or record types.

Edit: this works: notice the init on the property of the interface.

public interface ICountSomething
{
    public int Counter { get; init; }
}

public struct ActualStruct : ICountSomething
{
    public string Name { get; init; }

    public int Counter { get; init; }
}

public class Blah<T>
    where T : struct, ICountSomething
{
    public T DoSomethingWithGenericConstrainedToStruct(T input)
    {
        // Compiles ok
        return input with
        {
            Counter = input.Counter   1,
        };
    }

    public ActualStruct DoSomethingWithActualStruct(ActualStruct input)
    {
        // Compiles ok
        return input with
        {
            Counter = input.Counter   1,
        };
    }
}
  • Related