c# 8 开关表达式:找不到开关表达式的最佳类型
c# 8 switch expression: No best type was found for the switch expression
我在我的启动 class (.net core 3.1) 中添加了一个代码到 return 基于参数的类型,但我得到了编译时错误。
我在 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()
};
}
找到这个 link:https://github.com/dotnet/csharplang/issues/2728
感谢 Pavel 和 Marc,修复如下:
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()
};
}
您应该显式声明一种处理程序,而不是 var
IHandler handler = key switch //or BaseHandler handler = key switch
{
"myhandler1" => new MyHandler1(),
"myhandler2" => new MyHandler2(),
_ => throw new NotImplementedException()
};
在你的 sharplab 示例中,两个处理程序都实现了 IHandler
接口并继承了 BaseHandler
class,编译器根本不知道要使用哪种类型,你应该告诉它他明确地
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()
};
你只能为一个常量做这件事,编译器足够聪明,可以为你完成剩下的工作
var
很挑剔——它希望事情明确,而且 handler
应该在这里的类型并不明显,因为 MyHandler1
和 MyHandler2
是不同的类型;基本上,从 MyHandler1
和 MyHandler2
中选择一些通用的基类型或实现的接口,并使用它而不是 var
。在最坏的情况下,object
就足够了:
object handler = key switch
{
"myhandler1" => new MyHandler1(),
"myhandler2" => new MyHandler2(),
_ => throw new NotImplementedException()
};
编译器自己不会尝试这样做。
您正在处理协方差问题。您已指定 Func
的 return 类型应为 IHandler
,但此类型参数是不变的。因此,您实际上必须 return IHandler
,而不仅仅是实现它的 class。
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()
};
}
我在我的启动 class (.net core 3.1) 中添加了一个代码到 return 基于参数的类型,但我得到了编译时错误。
我在 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()
};
}
找到这个 link:https://github.com/dotnet/csharplang/issues/2728
感谢 Pavel 和 Marc,修复如下:
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()
};
}
您应该显式声明一种处理程序,而不是 var
IHandler handler = key switch //or BaseHandler handler = key switch
{
"myhandler1" => new MyHandler1(),
"myhandler2" => new MyHandler2(),
_ => throw new NotImplementedException()
};
在你的 sharplab 示例中,两个处理程序都实现了 IHandler
接口并继承了 BaseHandler
class,编译器根本不知道要使用哪种类型,你应该告诉它他明确地
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()
};
你只能为一个常量做这件事,编译器足够聪明,可以为你完成剩下的工作
var
很挑剔——它希望事情明确,而且 handler
应该在这里的类型并不明显,因为 MyHandler1
和 MyHandler2
是不同的类型;基本上,从 MyHandler1
和 MyHandler2
中选择一些通用的基类型或实现的接口,并使用它而不是 var
。在最坏的情况下,object
就足够了:
object handler = key switch
{
"myhandler1" => new MyHandler1(),
"myhandler2" => new MyHandler2(),
_ => throw new NotImplementedException()
};
编译器自己不会尝试这样做。
您正在处理协方差问题。您已指定 Func
的 return 类型应为 IHandler
,但此类型参数是不变的。因此,您实际上必须 return IHandler
,而不仅仅是实现它的 class。
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()
};
}