繁体   English   中英

C#泛型类作为参数与泛型类的调用方法相同的T

[英]C# Generic class as parameter with same T as called method of generic class

我想打电话:

Question<Entity> question = 
    Question<Entity>.Create(
        Choice.Create().
            AddFollowUpQuestion(Question.Create()).
            AddFollowUpQuestion(Question.Create()), 
        Choice.Create()
    );

但最好的 C# 允许我做的是:

Question<Entity> question = 
    Question<Entity>.Create(
        Choice<Entity>.Create().
            AddFollowUpQuestion(Question<Entity>.Create()).
            AddFollowUpQuestion(Question<Entity>.Create()), 
        Choice<Entity>.Create()
    );

我正在尝试清理一些代码,基本上只是添加了语法糖,所以我必须做的一些定义更容易阅读。

智能感知和编译器都知道他们期望参数是 Choice 类型,因为它是泛型类的方法。 但是它仍然需要我为传递的参数输入 T 的类型。

更抽象一点:我正在尝试创建一个顶级泛型类,其中所有也是泛型类型的属性都将对 T 使用相同的类型。

谁能帮我解决这个难题? 或者至少解释一下为什么我必须一遍又一遍地输入相同的类型?

简化的类定义:

public class Question<T> where T : Entity
{
    public static Question<T> Create(params Choice<T>[] choices)
    {
        return new Question<T>
        {
            Choices = choices
        };
    }

    private Choice<T>[] Choices { get; set; }
}

public class Choice<T> where T : Entity
{
    public static Choice<T> Create()
    {
        return new Choice<T>();
    }

    public Choice<T> AddFollowUpQuestion(Question<T> followUpQuestion)
    {
        FollowUpQuestions.Add(followUpQuestion);

        return this;
    }

    private static List<Question<T>> FollowUpQuestions { get; set; }
}

public abstract class Entity
{

}

C# 可以根据参数的类型推断您要调用的方法,但它无法推断出要调用产生所需类型参数的方法的类的类型:“类型推断魔术”仅适用单程。

本质上,你给编译器Choice.Create()表达式和它的结果被传递给一个期望Choice<Entity>的方法的事实,并要求它推断出Choice实际上是一个泛型类型(尽管事实上可能有系统中的一个非通用Choice ),并且它有一个返回Choice<T>Create()方法。 尽管编译器可能会这样做,但实现将是昂贵的,并且可能是一个破坏性的变化。

但是,您可以创建一个通用的辅助方法,为多个类提供相同的T ,如下所示:

static Question<T> MakeQuestion<T>() {
    return Question<T>.Create(Choice<T>.Create());
}

现在你可以打电话

Question<Entity> question = MakeQuestion<Entity>();

并且只传递一次类型参数。

编辑:编辑中更详细的示例而言,您应该能够通过引入一个在Entity上通用的工厂来缩短 API,并让您创建问题、跟进等。

class QuestionFactory<T> {
    public Question<T> CreateQuestion() {
        ...
    }
    public Choice<T> CreateChoice() {
        ...
    }
}

现在你可以这样做:

var qf = new QuestionFactory<Entity>();
var question = qf.CreateQuestion(
    qf.CreateChoice().
        AddFollowUpQuestion(qf.CreateQuestion()).
        AddFollowUpQuestion(qf.CreateQuestion()), 
    qf.CreateChoice()
);

一个常见的做法是为工厂方法创建非泛型类:

public static class Question {
    public static Question<T> Create<T>(Choice<T> choice) {
        return Question<T>.Create(choice);
    }
}

...
Question<Entity> question = Question.Create(Choice<Entity>.Create());

一种方法是将 Question.Create() 更改为不期望提供 Choice,而是创建 Choice 本身。 它使代码更简单,您可以实现您的目标。

public class Question<T> where T : Entity
{
    public static Question<T> Create()
    {
        return new Question<T>
        {
            Choice = Choice<T>.Create()
        };
    }

    private Choice<T> Choice { get; set; }
}

public class Choice<T> where T : Entity
{
    public static Choice<T> Create()
    {
        return new Choice<T>();
    }
}

public abstract class Entity
{

}

根据上下文,这可能是一个积极的变化,因为创建选择的责任转移到问题上,换句话说,您从创建选择的麻烦中抽象出 Question.Create() 的调用者。

另一方面,它增加了问题和选择的耦合。 更喜欢哪一个,取决于架构的其余部分。

当然,我假设Choice 中确实需要T。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM