代码之家  ›  专栏  ›  技术社区  ›  Fabio Marreco

可拓方法的C#型推理机制问题

c#
  •  0
  • Fabio Marreco  · 技术社区  · 6 年前

    im试图在c中创建一个api,通过解析依赖树和处理缓存等后台问题来评估依赖分析。

    我在这里不会深入讨论细节,bug我正在与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(ianalyticcresolver)”的类型参数。请尝试显式指定类型参数。

    我想我明白为什么会这样( TAnalytic 可能正在实现多个 IAnalytic<,> 接口)

    有办法解决这个问题吗?,还是必须显式调用带有类型参数的扩展方法(这对用户不太友好)

    2 回复  |  直到 6 年前
        1
  •  0
  •   fstam    6 年前

    不确定这正是您所要寻找的,但以下是您如何只需要在实例化期间或在实现中指定解析器的类型(您不能完全避免规范/强制转换):

    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();
        }
    }
    
        2
  •  0
  •   Fabio Marreco    6 年前

    谢谢大家, 但我最终创建了一个中介接口,如

    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”的隐式引用转换。

    避免我犯愚蠢的错误。