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

C#泛型类作为参数,T与泛型类的被调用方法相同,c#,generics,C#,Generics,我想打电话: Question<Entity> question = Question<Entity>.Create( Choice.Create(). AddFollowUpQuestion(Question.Create()). AddFollowUpQuestion(Question.Create()), Choice.Create() ); 问题= 问题,创建(

我想打电话:

Question<Entity> question = 
    Question<Entity>.Create(
        Choice.Create().
            AddFollowUpQuestion(Question.Create()).
            AddFollowUpQuestion(Question.Create()), 
        Choice.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.Create()。
AddFollowUpQuestion(Question.Create())。
AddFollowUpQuestion(Question.Create()),
Choice.Create()
);
我正在尝试清理一些代码,基本上只是添加语法糖,这样一些我必须做的定义更容易阅读

IntelisSense和编译器都知道,他们希望参数具有类型选择,因为它是泛型类的方法。但它仍然需要我为传递的参数键入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
{

}
公共类问题,其中T:实体
{
公共静态问题创建(参数选项[]选项)
{
返回新问题
{
选择=选择
};
}
私有选择[]选择{get;set;}
}
公共类选择,其中T:Entity
{
公共静态选择创建()
{
返回新选项();
}
公共选择添加后续问题(问题后续问题)
{
FollowUpQuestions.Add(followUpQuestion);
归还这个;
}
私有静态列表后续问题{get;set;}
}
公共抽象类实体
{
}

通常要做的事情是为factory方法创建非泛型类:

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=Question.Create(Choice.Create());
C#可以根据参数的类型推断出要调用的方法,但不能推断出要调用生成所需类型参数的方法的类的类型:“类型推断魔法”只有一种方式

本质上,您给编译器
Choice.Create()
表达式及其结果被传递给期望
Choice
的方法的事实,并要求它推断
Choice
实际上是泛型类型(尽管系统中可能存在非泛型
Choice
),它有一个
Create()
方法,返回
Choice
。虽然编译器可能做到这一点,但实现成本很高,而且可能是一个突破性的改变

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

static Question<T> MakeQuestion<T>() {
    return Question<T>.Create(Choice<T>.Create());
}
现在您可以执行以下操作:

var qf = new QuestionFactory<Entity>();
var question = qf.CreateQuestion(
    qf.CreateChoice().
        AddFollowUpQuestion(qf.CreateQuestion()).
        AddFollowUpQuestion(qf.CreateQuestion()), 
    qf.CreateChoice()
);
var qf=new QuestionFactory();
变量问题=qf.CreateQuestion(
qf.CreateChoice()。
AddFollowUpQuestion(qf.CreateQuestion())。
AddFollowUpQuestion(qf.CreateQuestion()),
qf.CreateChoice()
);

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

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
{

}
公共类问题,其中T:实体
{
公共静态问题创建()
{
返回新问题
{
Choice=Choice.Create()
};
}
私有选择{get;set;}
}
公共类选择,其中T:Entity
{
公共静态选择创建()
{
返回新选项();
}
}
公共抽象类实体
{
}
根据上下文的不同,这可能是一个积极的变化,因为创建选项的责任转移到了问题上,换句话说,您将Question.Create()的调用方从创建选项的麻烦中抽象出来

另一方面,它增加了问题和选择的耦合。 首选哪一个取决于体系结构的其余部分


当然,我认为T在选择中确实是必要的。

我明白这个想法,但恐怕在这种情况下它行不通。我在开篇文章中举了一个更复杂的例子,更清楚地表明我正在建立一种流畅的方式来添加选择,其中包含后续问题,而这些问题反过来又可以有选择……dasblinkenlight的答案有什么问题吗?太快了,伙计,这是周末;)我刚刚在评论中回复了他的回答。谢谢你解释为什么它不起作用。因为我正在尝试建立一种方法来流利地创建带有问题选择的问题。。。(我更新了开篇文章中的代码示例来说明这一点)我认为这不适合助手。恐怕我会把你的答复记为答案。让我考虑一下;)虽然不像我希望的那样令人满意,但你的解释似乎是正确的,你建议使用一家工厂确实可以为我解决这个问题。谢谢谢谢,但情况正好相反。理想情况下,我只会在最外层的问题上声明T的类型,并让c#magic告诉下面的所有方法。
var qf = new QuestionFactory<Entity>();
var question = qf.CreateQuestion(
    qf.CreateChoice().
        AddFollowUpQuestion(qf.CreateQuestion()).
        AddFollowUpQuestion(qf.CreateQuestion()), 
    qf.CreateChoice()
);
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
{

}