扩展方法的C#类型推断机制存在的问题

时间:2018-11-13 11:33:41

标签: c#

我正试图在C#中创建一个API,以通过解析其依赖关系树并在后台处理缓存以及其他问题来评估依赖分析。

在这里我不会详细介绍错误,我正在努力解决C#类型推断机制。

对于初学者。假设我有这些课程:

public interface IAnalytic {}

public interface IAnalytic<TInput, TOutput> : IAnalytic
{
    TOutput Calculate(TInput input);
}

public interface IAnalyticResolver <T> where T: IAnalytic
{
    object EvaluateUntyped();
}

public interface IResolver
{
    IAnalyticResolver<TAnalyticImpl> GetResolver<TAnalyticImpl> () where TAnalyticImpl : IAnalytic;
}

以一种方式,如果我有这样的课程:

public class ParseAnalytic : IAnalytic<string, int>
{
    public int Calculate(string input) => int.Parse(input);
}

我可以将我的API称为:

IResolver r = //..
int result = (int)r.GetResolver<ParseAnalytic>().EvaluateUntyped();

但是,我真的不喜欢必须在最后键入强制转换结果。因此,我尝试创建一种扩展方法来解决此问题:

public static class ResolverExtensions 
{
    public static TOutput Evaluate<TAnalytic, TInput, TOutput>(this IAnalyticResolver<TAnalytic> resolver)
        where TAnalytic : IAnalytic<TInput, TOutput>
    {
        return (TOutput)resolver.EvaluateUntyped();
    }
}

我期望通过调用此方法,C#将能够推断出TOutput类型,因为参数IAnalyticResolver<TAnalytic>具有限制where TAnalytic : IAnalytic<TInput, TOutput>

但是,当我尝试使用时却不是这样:

int i = r.GetResolver<ParseAnalytic>().Evaluate();

我得到一个

  

CS0411无法从用法中推断出方法'ResolverExtensions.Evaluate(IAnalyticResolver)'的类型参数。尝试显式指定类型参数。

我想我理解为什么会这样(TAnalytic可能实现多个IAnalytic<,>接口)

是否可以解决此问题?或者我是否必须使用类型实参显式调用扩展方法? (那不是非常用户友好)

2 个答案:

答案 0 :(得分:0)

不确定这正是您要寻找的,但是这是您仅需要在实例化或实现中指定解析器的类型的方法(您不能完全避免使用规范/广播)

public interface IAnalytic { }

public interface IAnalytic<TInput, TOutput> : IAnalytic
{
    TOutput Calculate(TInput input);
}

public interface IAnalyticResolver<T, TOutput> where T : IAnalytic
{
    TOutput Evaluate();
}

public interface IResolver<TOutput>
{
    IAnalyticResolver<TAnalyticImpl, TOutput> GetResolver<TAnalyticImpl>() where TAnalyticImpl : IAnalytic;
}

public class ParseAnalytic : IAnalytic<string, int>
{
    public int Calculate(string input) => int.Parse(input);
}

public class IntResolver : IResolver<int>
{
    public IAnalyticResolver<TAnalyticImpl, int> GetResolver<TAnalyticImpl>() where TAnalyticImpl : IAnalytic
    {
        throw new NotImplementedException();
    }
}

class Program
{
    static void Main(string[] args)
    {
        IResolver<int> r = new IntResolver();
        int result = r.GetResolver<ParseAnalytic>().Evaluate();
    }
}

答案 1 :(得分:0)

谢谢大家, 但是我最终创建了一个中间界面,例如

public interface IAnalytic<TOutput> : IAnalytic { }

并从其继承IAnalytic<,>

public interface IAnalytic<TInput, TOutput> : IAnalytic<TOutput>
{
    TOutput Calculate(TInput input);
}

还更改了IAnalyticResolverInterface使其可以使用:

public interface IAnalyticResolver<TAnalytic, TOutput> where TAnalytic : IAnalytic<TOutput>
{
    TOutput Evaluate();
}

public interface IResolver
{
    IAnalyticResolver<TAnalyticImpl, TOutput> GetResolver<TAnalyticImpl, TOutput> () 
           where TAnalyticImpl : IAnalytic<TOutput>;
}

有了这个,我可以调用解析器返回正确的类型。但是,我必须明确声明TOutput类型。

int i = r.GetResolver<ParseAnalytic, int>().Evaluate();

这是多余的,因为ParseAnalytic已经是IAnalytic<string, int>。但是我可以解决这个问题,因为在这种情况下至少int是唯一可接受的类型。如果我尝试写

double i = r.GetResolver<ParseAnalytic, double>().Evaluate();

编译器会说:

  

CS0311类型'UserQuery.ParseAnalytic'不能用作通用类型或方法'UserQuery.IResolver.GetResolver()'中的类型参数'TAnalyticImpl'。没有从'UserQuery.ParseAnalytic'到'UserQuery.IAnalytic'的隐式引用转换。

避免我犯愚蠢的错误。