c# 8 выражение переключателя: не найден лучший тип для выражения переключателя - PullRequest
2 голосов
/ 02 апреля 2020

Я добавил код в свой класс запуска (. net core 3.1), чтобы он возвращал тип, основанный на параметре, и я получаю ошибки во время компиляции.

Я создал работающий пример в sharplab . если выражение switch содержит строку или другие объекты, оно работает нормально.

рабочий пример 1:

var x = key switch
            {
                "myhandler1" => "something",
                "myhandler2" => "something else",
                _ => "default case"
            };

рабочий пример 2:

object obj =  s switch {
            "a" => new object(),
            "b" => new DateTime(),
            _ => throw new NotImplementedException()
        };

Пример ошибки:

interface IHandler { }
public class BaseHandler { }
public class MyHandler1: BaseHandler, IHandler { }
public class MyHandler2: BaseHandler, IHandler { }

class Program
{
    static void Main(string[] args)
    {

        var key = "myhandler1";

        var handler = key switch
        {
            "myhandler1" => new MyHandler1(),
            "myhandler2" => new MyHandler2(),
            _ => throw new NotImplementedException()
        };

        var x = key switch
        {
            "myhandler1" => "something",
            "myhandler2" => "something else",
            _ => "default case"
        };

        Console.WriteLine("Hello World!");
    }
}

исходная проблема (необходимо исправить):

serviceCollection.AddTransient<Func<string, IHandler>>(sp => key =>
            {
                return key switch
                {
                    Constants.Brand => sp.GetService<Handler1>(),
                    Constants.Series => sp.GetService<Handler2>(),
                    _ => throw new NotImplementedException()

                };
}

нашел эту ссылку : https://github.com/dotnet/csharplang/issues/2728

Благодаря Pavel и Mar c, ниже исправление:

serviceCollection.AddTransient<Func<string, IHandler>>(sp => key =>
            {
                return key switch
                {
                    Constants.Brand => (sp.GetService<Handler1>() as IHandler),
                    Constants.Series => (sp.GetService<Handler2>() as IHandler),
                    _ => throw new NotImplementedException()

                };
}

Ответы [ 3 ]

3 голосов
/ 02 апреля 2020

Вы должны явно объявить тип обработчика вместо var

IHandler handler = key switch //or BaseHandler handler = key switch
{
    "myhandler1" => new MyHandler1(),
    "myhandler2" => new MyHandler2(),
    _ => throw new NotImplementedException()
};

. В вашем sharplab образце оба обработчика реализуют интерфейс IHandler и наследуют класс BaseHandler, компилятор просто не знает, какой тип использовать, вы должны явно указать ему

interface IHandler { }
public class BaseHandler { }
public class MyHandler1 : BaseHandler, IHandler { }
public class MyHandler2 : BaseHandler, IHandler { }

То же самое верно для образца внедрения зависимости, вы должны явно объявить тип (при условии, что Handler1 и Handler2 реализовать IHandler)

return key switch
{
    Constants.Brand => sp.GetService<Handler1>(),
    Constants.Series => (IHandler) sp.GetService<Handler2>(),
    _ => throw new NotImplementedException()
};

Вы можете сделать это только для одной константы, компилятор достаточно умен, чтобы выполнить остальную работу за вас

1 голос
/ 02 апреля 2020

Вы имеете дело с проблемой ковариации. Вы указали, что тип возвращаемого значения Func должен быть IHandler, но этот тип параметра является инвариантным. Таким образом, вы должны возвращать IHandler, а не просто класс, который его реализует.

serviceCollection.AddTransient<Func<string, IHandler>>(sp => key =>
{
    return key switch
    {
        Constants.Brand => (IHandler)sp.GetService<Handler1>(),
        Constants.Series => (IHandler)sp.GetService<Handler2>(),
        _ => throw new NotImplementedException()
    };
}
1 голос
/ 02 апреля 2020

var суетливый - он хочет, чтобы вещи были однозначными, и неясно, какой тип handler должен быть здесь, поскольку MyHandler1 и MyHandler2 - это разные типы; в основном, выберите общий базовый тип или реализованный интерфейс из MyHandler1 и MyHandler2 и используйте его вместо var. В худшем случае object должно быть достаточно:

object handler = key switch
{
    "myhandler1" => new MyHandler1(),
    "myhandler2" => new MyHandler2(),
    _ => throw new NotImplementedException()
};

Компилятор не будет пытаться сделать это сам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...