泛型类型相互引用

Nik*_*hin 4 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, TValue> 
    where TResult : IResult<TValue, ITokenizer<TResult, TValue>>
{
    TResult Advance();
}
Run Code Online (Sandbox Code Playgroud)

它还有下一个用途:ITokenizer是一个不可变的类,用于按标记拆分字符串。我们可以调用Advance方法并获取Result:下一个标记和下一个标记器。所以,我想在Result类中存储令牌和标记器,并希望为此添加编译时约束。

现在我在构建这两个接口期间出现编译时错误。

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

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

public class Tokenizer : ITokenizer<Result, string>
{ /* implement interface */}
Run Code Online (Sandbox Code Playgroud)

谁能解释一下出了什么问题?也许为什么这是不可能的,或者如何使此代码正确?

PS 对于我的任务,我可以简单地使用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>'.
Run Code Online (Sandbox Code Playgroud)

Evk*_*Evk 5

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

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();
}
Run Code Online (Sandbox Code Playgroud)

它有点丑陋,但我认为会为您的目标工作:

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

}

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

}
Run Code Online (Sandbox Code Playgroud)

我认为主要问题不在于循环引用,而只是事实上编译器无法推断出泛型类型之间的隐式转换,除非您有所帮助。

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