C# 泛型类型相互引用

C# 泛型类型相互引用,c#,generics,generic-constraints,C#,Generics,Generic Constraints,我编写了简单的解析器,并希望实现下面两个接口: public interface IResult<TValue, TToken> where TToken : ITokenizer<IResult<TValue, TToken>, TValue> { TToken Tokenizer { get; } TValue Value { get; } } public interface ITokenizer<TResult, TV

我编写了简单的解析器,并希望实现下面两个接口:

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();
}
有人能解释一下怎么回事吗?也许是为什么这是不可能的,或者如何使这段代码正确

另外,对于我的任务,我可以简单地使用
IResult
接口而不受任何约束,但是我可以在不丢失约束的情况下实现它吗

编译器错误:

(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>'.
(3:22)类型“Test.IResult”不能用作泛型类型或方法“Test.ITokenizer”中的类型参数“TResult”。
没有从“Test.IResult”到的隐式引用转换
“Test.IResult”。
(10:22)类型“Test.ITokenizer”不能用作泛型类型或方法“Test.IResult”中的类型参数“TToken”。
没有从“Test.ITokenizer”到
“测试,伊藤酮化剂”。

您可以尝试向两个接口都添加一个类型约束,如下所示:

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();
}
公共接口IResult
伊藤健在哪里
TResult的位置:IResult{
TToken标记器{get;}
TValue值{get;}
}
公共接口伊藤健化器
TResult的位置:IResult
ToTokenizer的位置:ITokenizer{
TResult Advance();
}
这有点难看,但我认为这将有助于实现你的目标:

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

}

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

}
公共类结果:IResult
{
}
公共类标记器:ITokenizer{
}
我认为主要的问题不在于循环引用,而在于编译器无法推断泛型类型之间的隐式转换,除非您对此有所帮助

更新: 我认为您的接口在标记器和结果之间缺乏很强的关系。IResult接口说TToken可以是任何标记器,我的意思是与任何结果相关。所以它可以是
ITokenizer
ITokenizer
等等。但是您不能将
ITokenizer
分配给
ITokenizer
(即使结果实现相同的接口)-这是不同的类型。标记器接口也是如此。当您像上面那样更改接口时,现在很明显,
TToken
TResult
的标记器,同时
TResult
TTokenizer
的结果(现在这是两种具体类型,而不是接口,它们之间有着很强的关系)。

Update 请忽略这个答案,因为Evk的答案否定了这个答案。然而,我仍然把这个答案留在这里,因为如果其他人认为它与循环引用有关,这将有助于解释它显然与循环引用无关

问题是,当编译器试图编译第一个接口时,它需要编译第二个接口,但要编译第二个接口,它需要编译第一个接口。因此,它不能这样做,因为它不能得出结论。为了简化操作,此代码将得到与您相同的错误:

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

}

public interface ISecond<TSecond>
    where TSecond : IFirst<ISecond<TSecond>>
{ }
公共接口IFirst
其中tffirst:ISecond
{
}
公共接口等秒
其中t第二个:i第一个
{ }
但是下面的代码不会出错,因为没有循环引用,编译器可以得出结论:

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

}

public interface ISecond<TSecond>
    //where TSecond : IFirst<ISecond<TSecond>>
{ }
公共接口IFirst
其中tffirst:ISecond
{
}
公共接口等秒
//其中t第二个:i第一个
{ }

2件事:请将编译错误添加到您的帖子中,以便我们知道它是什么,然后也许可以告诉我们您正在尝试做什么,以便我们知道您选择此解决方案的原因。也许有更好的解决方案,你会有更多的想法。@CodingYoshi我不想深入讨论这种情况,因为我想理解为什么这段代码不能编译。我认为这有一个根本的原因,我现在不明白。但是你有一个循环引用:IResult类型约束依赖于ITokenizer,vica依赖于ITokenizer。错误很明显,它说它无法将IResult转换为IResult。我不知道你还想知道什么?@Evk但是为什么像
公共接口循环这样的简单循环引用允许T:circular
并且有效?看起来@Evk反驳了你关于循环引用的论点:-)他完全做到了。我正试着把我的脑袋绕过去。@NikitaSivukhin也看到了我对原因的想法(我认为这不是编译器无法推断的,但那些定义确实是错误的,不应该编译)。
public interface IFirst<TFirst>
    where TFirst : ISecond<IFirst<TFirst>>
{

}

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