[英]Trying to create C# method that outputs an object of a generic type that's nested inside another generic type
I'm currently working on writing a method that, for the sake of this problem, generates mazes.我目前正在编写一种方法,为了解决这个问题,它会生成迷宫。
Here's the (simplified) version of the classes involved:这是所涉及的类的(简化)版本:
public interface IAlgorithm<out MazeType> where MazeType : Maze
{
MazeType GoGenerate();
}
public class AlgorithmBacktrack : IAlgorithm<Maze>
{
public Maze GoGenerate()
{
//Do things
return new Maze();
}
}
public class Maze
{
}
public class MazeWithPath : Maze
{
}
What I'd like to do now is create helper to call this Algorithm:我现在想做的是创建助手来调用这个算法:
public class MazeGenerator
{
public static MAZETYPEGENERIC Generate<AlgorithmType>()
where AlgorithmType : IAlgorithm<MAZETYPEGENERIC>, new()
{
var alg = new AlgorithmType();
return alg.GoGenerate();
}
}
The thing that I can't get to work though is the MAZETYPEGENERIC.不过,我无法开始工作的是 MAZETYPEGENERIC。 Theoretically C# could know that whatever interface implementation of IAlgorithm I put in there would have the MAZETYPEGENERIC configured.从理论上讲,C# 可以知道我放在那里的任何 IAlgorithm 接口实现都会配置 MAZETYPEGENERIC。 However C# still want's me to add that as a Generic parameter to the method.但是 C# 仍然希望我将其作为通用参数添加到方法中。 Eg:例如:
public static MAZETYPEGENERIC Generate<AlgorithmType, MAZETYPEGENERIC>()
where AlgorithmType : IAlgorithm<MAZETYPEGENERIC>, new()
...
This however would mean that the invocation of this call would also require this parameter.然而,这意味着调用此调用也需要此参数。 Even though it could theoretically be inferred from the AlgorithmType.尽管理论上可以从 AlgorithmType 推断出来。
//Ideal way to call this method:
Maze m = MazeGenerator.Generate<AlgorithmBacktrack>();
//Actual way to call this after adding the additional generic parameter:
Maze m = MazeGenerator.Generate<AlgorithmBacktrack, Maze>();
I would love to see/hear if someone has an idea on how to accomplish option 1 (the ideal way of doing this).如果有人对如何完成选项 1(执行此操作的理想方式)有想法,我很乐意看到/听到。
One way to do this is to accept an instance of IAlgorithm<MAZETYPEGENERIC>
, and let type inference infer the type parameter MAZETYPEGENERIC
.一种方法是接受IAlgorithm<MAZETYPEGENERIC>
的实例,并让类型推断推断类型参数MAZETYPEGENERIC
。 Now you wouldn't need the AlgorithmType
type parameter现在您不需要AlgorithmType
类型参数
Maze m = MazeGenerator.Generate(new AlgorithmBacktrack());
...
public static MAZETYPEGENERIC Generate<MAZETYPEGENERIC>(IAlgorithm<MAZETYPEGENERIC> algorithm)
where MAZETYPEGENERIC : Maze {
return algorithm.GoGenerate();
}
You would have been able to access the type parameter of IAlgorithm
if C# interfaces used associated types (like Swift), rather than generics.如果 C# 接口使用关联类型(如 Swift)而不是 generics,您将能够访问IAlgorithm
的类型参数。 So it's not like this is completely impossible feature to have in a language.因此,这并不是一种语言中完全不可能的功能。 For a comparison see this post .比较看这篇文章。
If "instantiate the Algorithm class" is all you need, the closest I can get is probably by moving the call to GoGenerate
method out of Generate
method, like this:如果您只需要“实例化算法类”,那么我能得到的最接近的可能是将GoGenerate
方法的调用移出Generate
方法,如下所示:
static T Generate<T>() where T : IAlgorithm<Maze>, new()
{
return new T();
}
Maze m = MazeGenerator.Generate<AlgorithmBacktrack>().GoGenerate();
// I made the algorithm class up
MazeWithPath m = MazeGenerator.Generate<AlgorithmBacktrack2>().GoGenerate();
Or if the type of local variable m
is always Maze
, you could also do something like:或者,如果局部变量m
的类型始终是Maze
,您还可以执行以下操作:
static Maze Generate<T>() where T : IAlgorithm<Maze>, new()
{
return new T().GoGenerate();
}
Also want to comment on也想评论
Theoretically C# could know that whatever interface implementation of IAlgorithm I put in there理论上 C# 可以知道我放在那里的任何 IAlgorithm 接口实现
I hope C# would not (like it currently does).我希望 C# 不会(就像现在一样)。 T
in your case is covariant .在您的情况下, T
是covariant 。 If T
is implementation of IAlgorithm<MazeWithPath>
, both Maze
, MazeWithPath
and object
are semantically correct for return type.如果T
是IAlgorithm<MazeWithPath>
的实现,则Maze
、 MazeWithPath
和object
在语义上对于返回类型都是正确的。
The compiler can't choose one without knowing the context of your code.编译器无法在不知道代码上下文的情况下选择一个。 And if it can, it may choose a wrong one for you:如果可以,它可能会为您选择错误的:
// This is only correct when the compiler chooses MazeWithPath as return type
// It will become invalid if compiler chooses Maze or object
MazeWithPath m = Generate<AlgorithmBacktrack2>();
In saying that, making Generate
method to take two generic parameters might make more sense IMO.话虽如此,使Generate
方法采用两个通用参数可能更有意义 IMO。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.