如何仅对特定类型的 select 项目实施功能?
How to implement a function to select items only of specific types?
上下文
我有一个Question
class。它有三个子classes:
ChoiceQuestion
ShortTextQuestion
LongTextQuestion
我有一个 Repository
class 其中有一个 IEnumerable<Question>
.
代码
问题class层次结构和容器class存储库:
class Question {}
class ChoiceQuestion : Question {}
class ShortTextQuestion : Question {}
class LongTextQuestion : Question {}
class Repository
{
IEnumerable<Question> Questions { get; set; }
}
问题
我想从这些存储库中为 Questionnaire
选择几个问题。
我有一个 IQuestionnaireBuilder
,它有一个 AddSource()
方法,可以帮助配置从哪个存储库中挑选问题以及如何挑选问题。我有 QuestionnaireSource
class 保存此配置。
目前,我能够指定从哪个存储库中选择,每个难度选择多少问题。我想指定它应该只选择特定子类型的问题。
例如,要选择的问题必须是 ChoiceQuestion
或 ShortTextQuestion
。我遇到过 System.Type
,但我想限制类型,以便它们必须派生自 Question
。
代码
IQuestionnaireBuilder
interface IQuestionnaireBuilder
{
IQuestionnaireBuilder AddSource(Action<QuestionnaireSource> source);
}
问卷来源
class QuestionnaireSource
{
public Repository Repository { get; set; }
public IDictionary<QuestionDifficulty, int> { get; set; }
// <Property/method to configure which subclasses to include, they must derive from Question>
}
问题难度
enum QuestionDifficulty
{ Easy, Medium, Hard }
IQuestionnaireBuilder builder = new QuestionnaireBuilder();
Repository repo1 = someExternalProvider.GetRepo(1);
Repository repo2 = someExternalProvider.GetRepo(2);
builder
.AddSource(source => {
source.Repository = repo1;
source.Count[QuestionDifficulty.Easy] = 10;
source.Count[QuestionDifficulty.Medium] = 7;
source.Count[QuestionDifficulty.Hard] = 3;
source.PickOnlySpecificSubclassesOfQuestion() // how to implement this?
})
.AddSource(source => {
source.Repository = repo2;
source.Count[QuestionDifficulty.Easy] = 30;
source.Count[QuestionDifficulty.Medium] = 15;
source.Count[QuestionDifficulty.Hard] = 5;
source.PickOnlySpecificSubclassesOfQuestion() // how to implement this?
})
在上面的代码片段中,如何实现 PickOnlySpecificSubclassesOfQuestion()
部分?
一种方法是使您的 PickOnlySpecificSubclassesOfQuestion
通用,并向其传递一个代表您想要的问题类型的参数。
public void PickOnlySpecificSubclassesOfQuestion<T>()
where T : Question
在该方法中,您可以获得一个 System.Type 表示请求的问题类型,如下所示:
Type desiredTypeOfQuestion = typeof(T);
然后,给定 IEnumerable
个包含所有不同类型问题的问题,您可以使用 Linq 和反射从所需类型中找到可分配的问题:
return myQuestions.Where(q => q.GetType().IsAssignableFrom(desiredTypeOfQuestion));
我敢肯定还有其他方法也行得通,但这是最容易想到的方法。
这就是我使用委托完成的方式。我在 System.Predicate<T>
类型的 QuestionnaireSource
中添加了 Filter
属性。 System.Predicate<T>
是一个委托,定义如下:
public delegate bool Predicate<in T>(T obj);
您也可以使用 Func<Question, bool>
或您自己的委托类型。
在我的 QuestionnaireSource
class 中,我添加了 Filter
属性:
class QuestionnaireSource
{
public Repository Repository { get; set; }
public IDictionary<QuestionDifficulty, int> { get; set; }
public Predicate<Question> Filter { get; set; }
}
现在我可以传递一个 lambda 表达式,如下所示:
question => question is ChoiceQuestion
由于 C# 与 is
的模式匹配,现在我可以更灵活地进行过滤。
我可以在构建问卷时使用 QuestionnaireBuilder
的 AddSource()
方法对其进行如下配置:
builder
.AddSource(source => {
source.Repository = repo1;
source.Count[QuestionDifficulty.Easy] = 10;
source.Count[QuestionDifficulty.Medium] = 7;
source.Count[QuestionDifficulty.Hard] = 3;
source.Filter = question => question is ChoiceQuestion
});
现在我可以过滤掉或包含多种类型:
question => question is ChoiceQuestion || question is ShortTextQuestion
不仅如此,我还可以使用其他条件进行筛选,例如问题文本:
question => question.Text.Trim().StartsWith("What");
@benjamin 的回答在您只想 select 一个子类型时也有效,但是如果要 select 编辑或忽略多个类型,这种过滤方法似乎更灵活一些。
上下文
我有一个Question
class。它有三个子classes:
ChoiceQuestion
ShortTextQuestion
LongTextQuestion
我有一个 Repository
class 其中有一个 IEnumerable<Question>
.
代码
问题class层次结构和容器class存储库:
class Question {}
class ChoiceQuestion : Question {}
class ShortTextQuestion : Question {}
class LongTextQuestion : Question {}
class Repository
{
IEnumerable<Question> Questions { get; set; }
}
问题
我想从这些存储库中为 Questionnaire
选择几个问题。
我有一个 IQuestionnaireBuilder
,它有一个 AddSource()
方法,可以帮助配置从哪个存储库中挑选问题以及如何挑选问题。我有 QuestionnaireSource
class 保存此配置。
目前,我能够指定从哪个存储库中选择,每个难度选择多少问题。我想指定它应该只选择特定子类型的问题。
例如,要选择的问题必须是 ChoiceQuestion
或 ShortTextQuestion
。我遇到过 System.Type
,但我想限制类型,以便它们必须派生自 Question
。
代码
IQuestionnaireBuilder
interface IQuestionnaireBuilder
{
IQuestionnaireBuilder AddSource(Action<QuestionnaireSource> source);
}
问卷来源
class QuestionnaireSource
{
public Repository Repository { get; set; }
public IDictionary<QuestionDifficulty, int> { get; set; }
// <Property/method to configure which subclasses to include, they must derive from Question>
}
问题难度
enum QuestionDifficulty
{ Easy, Medium, Hard }
IQuestionnaireBuilder builder = new QuestionnaireBuilder();
Repository repo1 = someExternalProvider.GetRepo(1);
Repository repo2 = someExternalProvider.GetRepo(2);
builder
.AddSource(source => {
source.Repository = repo1;
source.Count[QuestionDifficulty.Easy] = 10;
source.Count[QuestionDifficulty.Medium] = 7;
source.Count[QuestionDifficulty.Hard] = 3;
source.PickOnlySpecificSubclassesOfQuestion() // how to implement this?
})
.AddSource(source => {
source.Repository = repo2;
source.Count[QuestionDifficulty.Easy] = 30;
source.Count[QuestionDifficulty.Medium] = 15;
source.Count[QuestionDifficulty.Hard] = 5;
source.PickOnlySpecificSubclassesOfQuestion() // how to implement this?
})
在上面的代码片段中,如何实现 PickOnlySpecificSubclassesOfQuestion()
部分?
一种方法是使您的 PickOnlySpecificSubclassesOfQuestion
通用,并向其传递一个代表您想要的问题类型的参数。
public void PickOnlySpecificSubclassesOfQuestion<T>()
where T : Question
在该方法中,您可以获得一个 System.Type 表示请求的问题类型,如下所示:
Type desiredTypeOfQuestion = typeof(T);
然后,给定 IEnumerable
个包含所有不同类型问题的问题,您可以使用 Linq 和反射从所需类型中找到可分配的问题:
return myQuestions.Where(q => q.GetType().IsAssignableFrom(desiredTypeOfQuestion));
我敢肯定还有其他方法也行得通,但这是最容易想到的方法。
这就是我使用委托完成的方式。我在 System.Predicate<T>
类型的 QuestionnaireSource
中添加了 Filter
属性。 System.Predicate<T>
是一个委托,定义如下:
public delegate bool Predicate<in T>(T obj);
您也可以使用 Func<Question, bool>
或您自己的委托类型。
在我的 QuestionnaireSource
class 中,我添加了 Filter
属性:
class QuestionnaireSource
{
public Repository Repository { get; set; }
public IDictionary<QuestionDifficulty, int> { get; set; }
public Predicate<Question> Filter { get; set; }
}
现在我可以传递一个 lambda 表达式,如下所示:
question => question is ChoiceQuestion
由于 C# 与 is
的模式匹配,现在我可以更灵活地进行过滤。
我可以在构建问卷时使用 QuestionnaireBuilder
的 AddSource()
方法对其进行如下配置:
builder
.AddSource(source => {
source.Repository = repo1;
source.Count[QuestionDifficulty.Easy] = 10;
source.Count[QuestionDifficulty.Medium] = 7;
source.Count[QuestionDifficulty.Hard] = 3;
source.Filter = question => question is ChoiceQuestion
});
现在我可以过滤掉或包含多种类型:
question => question is ChoiceQuestion || question is ShortTextQuestion
不仅如此,我还可以使用其他条件进行筛选,例如问题文本:
question => question.Text.Trim().StartsWith("What");
@benjamin 的回答在您只想 select 一个子类型时也有效,但是如果要 select 编辑或忽略多个类型,这种过滤方法似乎更灵活一些。