15

我在我的启动类(.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

感谢PavelMarc,以下是修复:

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()

                };
}
4

3 回答 3

23

您应该显式声明一种处理程序,而不是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 { }

依赖注入示例也是如此,您应该显式声明一个类型(假设Handler1Handler2实现IHandler

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

您只能为一个常量执行此操作,编译器足够聪明,可以为您完成其余的工作

于 2020-04-02T14:03:35.037 回答
2

您正在处理协方差问题。您已经指定了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()
    };
}
于 2020-04-02T14:30:58.793 回答
1

varhandler很挑剔——它想要明确的东西,而且这里应该是什么类型并不明显,MyHandler1因为MyHandler2它们是不同的类型;基本上,从 and 中选择一些常见的基本类型或实现的接口MyHandler1MyHandler2并使用它来代替var. 在最坏的情况下,object应该足够了:

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

编译器不会尝试自己执行此操作。

于 2020-04-02T14:03:39.603 回答