【问题标题】:c# 8 switch expression: No best type was found for the switch expressionc# 8 switch 表达式:没有找到 switch 表达式的最佳类型
【发布时间】:2020-07-14 12:42:24
【问题描述】:

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

                };
}

【问题讨论】:

  • 如果Handler1Handler2 有一个共同的基本类型/接口就可以了。
  • 由于DateTime 可以向下转换为object,这是可行的,但我认为MyHandler2 不会从MyHandler1 继承,反之亦然。如果这两种类型有一个共同的基本类型,您可以使用它而不是var 来为编译器提供足够的知识。 IE。 MyHandlerBase handler = key switch { ... };.
  • MyHandler1MyHandler2 是否共享一个共同的基本类型?也许用它代替var
  • @MarcGravell 是的,它们都有 baseType 和接口。在sharplab中,我使用了BaseHandler/Ihandler,它解决了这个问题,但是当我在启动DI类中应用相同的更改时,它仍然给出错误。
  • 也许return (IHandler) key switch... ?

标签: c# asp.net-core .net-core c#-8.0 switch-expression


【解决方案1】:

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

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

【讨论】:

  • 感谢它确实修复了它,但它没有修复依赖注入中的错误,我已经更新了我的问题,
  • @KamranPervaiz 你能在你的问题中分享来自 DI 的竞争样本吗?
  • @KamranPervaiz 您是否尝试过关注此comment 并明确声明Func
  • 不确定如何在启动类中明确说明。
【解决方案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()
    };
}

【讨论】:

    【解决方案3】:

    var 很挑剔 - 它希望事情明确,并且由于MyHandler1MyHandler2 是不同的类型,因此handler 应该在这里是什么类型并不明显;基本上,从MyHandler1MyHandler2 中选择一些通用的基本类型或实现的接口,并使用它来代替var。在最坏的情况下,object 就足够了:

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

    编译器不会自己尝试这样做。

    【讨论】:

    • 谢谢,我更新了关于 DI 的问题。不确定为什么当sharplab 为通用基类型工作时它不适用于依赖注入
    猜你喜欢
    • 1970-01-01
    • 2020-01-10
    • 2020-03-18
    • 2021-05-18
    • 2020-05-10
    • 1970-01-01
    • 2020-03-14
    • 2020-04-30
    • 2016-01-24
    相关资源
    最近更新 更多