C#Generic class作为参数,具有相同的T作为泛型类的调用方法

时间:2016-03-19 10:57:18

标签: c# generics

我想打电话:

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
{

}

3 个答案:

答案 0 :(得分:1)

C#可以根据参数的类型推断出你想要调用的方法,但它不能推断出要调用产生所需类型参数的方法的类的类型:“类型推理魔法“只走一条路。

基本上,您给出了编译器Choice.Create()表达式以及将其结果传递给期望Choice<Entity>的方法的事实,并要求它推导出Choice实际上是泛型类型(尽管系统中可能存在非泛型Choice),并且它具有返回Create()的{​​{1}}方法。尽管编译器可能会这样做,但实现起来会很昂贵,并且可能会发生重大变化。

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

T

现在你可以打电话了

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

并仅传递一次type参数。

编辑:就编辑中更精细的示例而言,您应该能够通过在{{上引入通用的工厂来缩短API。 1}},让你创建问题,跟进等等。

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

现在你可以这样做:

Entity

答案 1 :(得分:0)

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

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());

答案 2 :(得分:0)

一种方法是将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()的调用者。 / p>

另一方面,它增加了Question和Choice的耦合。 哪一个更受欢迎,取决于架构的其余部分。

当然,我认为在选择中确实需要T。