2016-11-19 67 views
2

我写简单的解析器和接下来要实现两个接口:泛型类型的引用对方

public interface IResult<TValue, TToken> 
    where TToken : ITokenizer<IResult<TValue, TToken>, TValue> 
{ 
    TToken Tokenizer { get; } 
    TValue Value { get; } 
} 

public interface ITokenizer<TResult, TValue> 
    where TResult : IResult<TValue, ITokenizer<TResult, TValue>> 
{ 
    TResult Advance(); 
} 

它旁边目的:ITokenizer是通过标记分割字符串的不可变类。我们可以调用Advance方法并获得Result:下一个令牌和下一个令牌。所以,我想在Result类中存储令牌和标记器,并且希望为此添加编译时间约束。

现在我在构造这两个接口的过程中出现编译时错误。

我认为下一个类可以实现与所有约束接口:

public class Result : IResult<string, Tokenizer> 
{ /* implement interface */} 

public class Tokenizer : ITokenizer<Result, string> 
{ /* implement interface */} 

谁能解释什么是错的?也许为什么这是不可能的或如何使这段代码正确?

P.S.对于我的任务,我可以简单地使用IResult<TValue, TToken>接口没有任何限制,但我可以实现这个没有失去约束?

编译器错误:

(3:22) The type 'Test.IResult<TValue,TToken>' cannot be used as type parameter 'TResult' in the generic type or method 'Test.ITokenizer<TResult,TValue>'. 
There is no implicit reference conversion from 'Test.IResult<TValue,TToken>' to 
'Test.IResult<TValue,Test.ITokenizer<Test.IResult<TValue,TToken>,TValue>>'. 
(10:22) The type 'Test.ITokenizer<TResult,TValue>' cannot be used as type parameter 'TToken' in the generic type or method 'Test.IResult<TValue,TToken>'. 
There is no implicit reference conversion from 'Test.ITokenizer<TResult,TValue>' to 
'Test.ITokenizer<Test.IResult<TValue,Test.ITokenizer<TResult,TValue>>,TValue>'. 
+0

2件事:请将编译错误添加到您的文章中,以便我们知道它是什么,其次可能告诉我们您正在尝试做什么,因此我们知道您为什么选择此解决方案。可能有更好的解决方案,你会得到更多的想法。 – CodingYoshi

+0

@CodingYoshi我不想深究这种情况,因为我想了解为什么这段代码不能编译。我认为这有一个潜在的基本原因,我现在不明白。 –

+0

但您有循环引用:IResult类型约束取决于ITokenizer和vica。 – Evk

回答

2

你可以尝试多了一个类型的约束添加到两个接口,这样的:

public interface IResult<TValue, TToken, TResult> 
    where TToken : ITokenizer<TResult, TValue, TToken> 
    where TResult : IResult<TValue, TToken, TResult> { 
    TToken Tokenizer { get; } 
    TValue Value { get; } 
} 

public interface ITokenizer<TResult, TValue, TTokenizer> 
    where TResult : IResult<TValue, TTokenizer, TResult> 
    where TTokenizer : ITokenizer<TResult, TValue, TTokenizer> { 
    TResult Advance(); 
} 

更丑了一点,但我想会的工作你的目标是:

public class Result : IResult<string, Tokenizer, Result> 
{ 

} 

public class Tokenizer : ITokenizer<Result, string, Tokenizer> { 

} 

我觉得主要问题不是循环引用,而只是事实编译器不能d在您的泛型类型之间进行隐式转换,直到您有所帮助。

更新: 我认为你的接口缺乏Tokenizer和Result之间的强关系。 IResult接口说,TToken可以是任何分词器,我的意思是相关任何结果。所以它可以是ITokenizer<Result1>ITokenizer<Result2>等等。但是,您不能将ITokenizer<Result1>指定为ITokenizer<Result2>(即使结果实现相同的界面) - 这是不同的类型。标记器接口也是如此。当你改变如上所述的界面时,现在很清楚TTokenTResult的标记器,同时TResultTTokenizer的结果(现在它们是两个具体类型,而不是接口,它们之间具有强关系)。

+0

谢谢!但对我而言,无法推断编译器仍然不清楚...... –

+0

@NikitaSivukhin另请参阅我对这些原因的看法(我认为它不是编译器无法推论出来,但这些定义真的是错误的,不应该编译)。 – Evk

0

更新 由于Evk的回答否定了此答案,请不用回答这个问题。但是,我仍然在这里留下这个答案,因为如果别人认为它与循环引用有关,它将有助于解释它显然没有。

问题是当编译器试图编译第一个接口时,它需要编译第二个接口但编译第二个接口,它需要编译第一个接口。因此,它不能这样做,因为它不能得出结论。为了让事情变得更简单,这段代码将得到同样的错误和你:

public interface IFirst<TFirst> 
    where TFirst : ISecond<IFirst<TFirst>> 
{ 

} 

public interface ISecond<TSecond> 
    where TSecond : IFirst<ISecond<TSecond>> 
{ } 

但是代码,因为没有循环引用,编译器可以得出结论如下不会得到错误:

public interface IFirst<TFirst> 
    where TFirst : ISecond<IFirst<TFirst>> 
{ 

} 

public interface ISecond<TSecond> 
    //where TSecond : IFirst<ISecond<TSecond>> 
{ } 
+0

看起来像@Evk反驳你的参考循环参考:-) –

+1

他完全做到了。我正试图围住它。 – CodingYoshi