这里我有一个简单的场景,有两种方法,我从彼此得到一个模糊的调用:
这是我的代码:
public IEnumerable<JobsViewModel> GetJobsViewModels(Guid vesselId, int status, Func<JobsNoSubsYpdcResult, bool> predicate = null)
=> predicate == null
? Mapper.Map<IEnumerable<JobsViewModel>>(_procedureService.Tech_GetJobsNoSubsYPDC(vesselId, status))
: Mapper.Map<IEnumerable<JobsViewModel>>(_procedureService.Tech_GetJobsNoSubsYPDC(vesselId, status).Where(predicate));
public IEnumerable<JobsViewModel> GetJobsViewModels(Guid vesselId, int status, Func<JobsViewModel, bool> predicate = null)
=> predicate == null
? GetJobsViewModels(vesselId, status)
: GetJobsViewModels(vesselId, status).Where(predicate);
我不喜欢更改方法的名称,但是从第二个方法我得到错误消息:
不明确的调用
我想从第二个调用第一个,就像我想要做的那样,是否有人知道如何在不更改方法名称的情况下执行此操作,否则我应该更改它们?
答案 0 :(得分:4)
处理此问题的最佳方法是不要有两个含糊不清的重载,这样您就不需要记住如何在您调用它们的任何地方进行特殊处理。
由于您的第二个重载调用第一个,我会说最合理的操作原因是删除该委托的默认参数值:
public IEnumerable<JobsViewModel> GetJobsViewModels(Guid vesselId, int status, Func<JobsViewModel, bool> predicate)
=> predicate == null
? GetJobsViewModels(vesselId, status)
: GetJobsViewModels(vesselId, status).Where(predicate);
您还应该推断调用此方法指定委托参数的能力,但明确指定null
。如果这无论如何都不可能(即三元表达式的第一部分实际上不会被使用)那么我会简化整个方法:
public IEnumerable<JobsViewModel> GetJobsViewModels(Guid vesselId, int status, Func<JobsViewModel, bool> predicate)
=> GetJobsViewModels(vesselId, status).Where(predicate);
现在,尽管如此,我还是没有真正看到第二种方法的重点,就像在外面我无论如何都可以简单地抓住.Where(...)
过滤器。由于该方法不会对此谓词做任何巧妙的事情,比如传递它并在较低级别上执行它,或者优化它获取数据的方式,那么这实际上只是语法糖。
然而,这只是我的意见,而且我承认并不知道如何使用这一切。我的真正答案是第一部分,但你真的应该避免声明含糊不清的方法。
另请参阅此问题:Breaking change in method overload resolution in C# 6 - explanation?。
当Roslyn进入场景时,重载分辨率发生了变化,他们决定记录更改并将其更改,而不是重新引入旧的&#34;错误&#34;。
答案 1 :(得分:2)
您需要提供可选参数并使其类型对编译器清晰,即使值为null
:
GetJobsViewModels(vesselId, status, (Func<JobsNoSubsYpdcResult, bool>)null)
编辑:在OP提出的特定情况下,Lasse's solution更可取。
另一方面,这个答案中显示的解决方案通常可以应用,当消除过载时,其他重载没有可选的非可选参数(例如,在调用某些{时) {3}}构造函数)。答案 2 :(得分:2)
执行此操作的唯一方法是使用适当类型的值填充可选参数,以便编译器知道要选择哪个重载。例如:
public IEnumerable<JobsViewModel> GetJobsViewModels(
Guid vesselId,
int status,
Func<JobsViewModel, bool> predicate = null)
{
// We're never filtering by JobsNoSubsYpdcResult, but this
// satisfies overload resolution
Func<JobsNoSubsYpdcResult, bool> resultPredicate = null;
return predicate == null
? GetJobsViewModels(vesselId, status, resultPredicate)
: GetJobsViewModels(vesselId, status, resultPredicate).Where(predicate);
}
或者为了避免重复:
public IEnumerable<JobsViewModel> GetJobsViewModels(
Guid vesselId,
int status,
Func<JobsViewModel, bool> predicate = null)
{
// We're never filtering by JobsNoSubsYpdcResult, but this
// satisfies overload resolution
Func<JobsNoSubsYpdcResult, bool> resultPredicate = null;
var allResults = GetJobsViewModels(vesselId, status, resultPredicate);
return predicate == null
? allResults : allResults.Where(predicate);
}
或者为了避免重复更多重复,请引入您自己的扩展方法:
public static IEnumerable<T> OptionalWhere<T>(
this IEnumerable<T> source,
Func<T, bool> predicate) =>
predicate == null ? source : source.Where(predicate);
然后你可以重写两种方法来使用它:
public IEnumerable<JobsViewModel> GetJobsViewModels(Guid vesselId, int status, Func<JobsNoSubsYpdcResult, bool> predicate = null) =>
Mapper.Map<IEnumerable<JobsViewModel>>(_procedureService.Tech_GetJobsNoSubsYPDC(vesselId, status))
.OptionalWhere(predicate);
public IEnumerable<JobsViewModel> GetJobsViewModels(
Guid vesselId,
int status,
Func<JobsViewModel, bool> predicate = null)
{
// We're never filtering by JobsNoSubsYpdcResult, but this
// satisfies overload resolution
Func<JobsNoSubsYpdcResult, bool> resultPredicate = null;
return GetJobsViewModels(vesselId, status, resultPredicate)
.OptionalWhere(predicate);
}
(如果您乐意将null
转换为Func<JobsNoSubsYpdcResult, bool>
或使用静态字段,则可以使用表达式身体方法。)
答案 3 :(得分:1)
如果你真的想要你想说的话,你需要传递正确的谓词参数,例如: GetJobsViewModels(vesselId, status, new Func<JobsNoSubsYpdcResult, bool>( x => true ));