简体   繁体   中英

Nullable generic reference type

I have the following (working) service implemented using C#8, but with nullable reference types disabled:

public class Foo { }

public interface IFooService
{
    Task<T> Get<T>() where T : Foo;
}

public FooService : IFooService
{
    async Task<T> IFooService.Get<T>() { /* returns either a valid Foo implementation or null */ }
}

I tried to enable C#8 nullable reference types, but can't seem to get rid of errors or warnings, whatever I do. The new interface type is:

public interface IFooService
{
    // T IS nullable AND a reference type.
    // There is no ambiguity as of 'T?' meaning here, because it can't be a struct.
    Task<T?> Get<T>() where T : Foo;
}

When I use the following implementation:

public class FooService : IFooService
{
    async Task<T?> IFooService.Get<T>() { /* ... */ }
}

I get the error:

'FooService' does not implement interface member 'IFooService.Get<T>()'

Which I don't understand because the signatures in the interface and in the implementation are exactly the same.

However, when I implement the interface as this (which is the signature Visual Studio's auto-implementation generates):

public class FooService : IFooService
{
    async Task<T> IFooService.Get<T>() { /* ... */ }
}

I get the following warning:

Nullability of reference types in return type doesn't match implemented member 'Task<T?> IFooService.Get<T>()'.

You need to add the generic constraint to your implementation:

public class FooService : IFooService
{
    async Task<T?> IFooService.Get<T>() where T : class
    {
        /* ... */ 
    }
}

It's interesting how Visual Studio doesn't add the T? to the implementation it generates. I suspect this is a bug in the editor.

You mention that your type constriant is actually against a Foo . This means your code would look like this:

public class Foo
{
}

public interface IFooService
{
    // T IS nullable AND a reference type.
    // There is no ambiguity as of 'T?' meaning here, because it can't be a struct.
    Task<T?> Get<T>() where T : Foo;
}

public class FooService : IFooService
{
    async Task<T?> IFooService.Get<T>() where T : class
    {
        throw new NotImplementedException();
    }
}

The type constraint is on the interface, but on the implemetation you can't specify an actual type name, but you can indicate it has to be a class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM