首页 > 解决方案 > 等效的 Java 通用循环引用 C#

问题描述

我正在用 C# 移植一个 Java 库,我发现这个奇怪的类使用了泛型循环引用:

public static class UserAgentAnalyzerDirectBuilder<UAA extends UserAgentAnalyzerDirect, B extends UserAgentAnalyzerDirectBuilder<UAA, B>> 
{
   // Implementation
}

我不能很好地理解循环引用是如何工作的,但正如我所见,确实是可能的。

该代码可以很容易地转换为 C#:

public class UserAgentAnalyzerDirectBuilder<UAA, B> where UAA: UserAgentAnalyzerDirect where B: UserAgentAnalyzerDirectBuilder<UAA, B>
{
  // Implementation
}

假设我的等效类是正确的,我需要实现实例化那个奇怪的类的方法。

在Java中我有这个代码:

public static UserAgentAnalyzerDirectBuilder<? extends UserAgentAnalyzer, ? extends UserAgentAnalyzerDirectBuilder<?, ?>> newBuilder() {
    return new UserAgentAnalyzerDirectBuilder<>(new UserAgentAnalyzer());
}

在 C# 中,我尝试使用以下方法重现:

public static UserAgentAnalyzerDirectBuilder<UAA, UserAgentAnalyzerDirectBuilder<UAA, B>> newBuilder<UAA, B>() 
            where UAA: UserAgentAnalyzerDirect
            where B: UserAgentAnalyzerDirectBuilder<UAA, B>
        {
            return new UserAgentAnalyzerDirectBuilder<UAA, UserAgentAnalyzerDirectBuilder<UAA, B>> (new UserAgentAnalyzer());
        }

但它不起作用。我想知道我是否做错了什么,或者在 C# 泛型中循环引用是否确实是可能的。

标签: c#generics

解决方案


你看到的不是循环引用。类型参数约束只允许您传入一个类型,该类型是约束指定的泛型类型的后代。

下面的代码示例编译,我认为会做你需要的:

public class UserAgentAnalyzerDirect { }

public class UserAgentAnalyzerDirectBuilder<UAA, B> 
    where UAA : UserAgentAnalyzerDirect 
    where B : UserAgentAnalyzerDirectBuilder<UAA, B>
{
    // this method is supposed to implement the effect of the 
    // constructor in the original Java code
    public void SetUAA(UAA a) { }

    // further implementation
}

public static UserAgentAnalyzerDirectBuilder<UAA, B> NewBuilder<UAA, B>()
    where UAA : UserAgentAnalyzerDirect, new()
    where B : UserAgentAnalyzerDirectBuilder<UAA, B>, new()
{
    // Unlike in Java, C# allows instantiating generic type parameters only using 
    // a parameter-less constructor. Hence we use the SetUAA method here instead.
    var a = new UAA();
    var b = new B();
    b.SetUAA(a);
    return b;
}

然后你可以像这样创建上面通用类的自定义后代:

public class CustomUserAgentAnalyzerDirect : UserAgentAnalyzerDirect { }

public class CustomUserAgentAnalyzerDirectBuilder : UserAgentAnalyzerDirectBuilder<CustomUserAgentAnalyzerDirect, CustomUserAgentAnalyzerDirectBuilder> { }

推荐阅读