我有一个抽象类GenericModel
,它定义了一个模板方法,如下所示:
public virtual string DoStuff<TType>(IEnumerable<TType> input)
where TType : GenericModel { return null; }
然后我有一个继承自GenericModel
BasicModel
的类,它代表GenericModel
的某个子集,它们有足够的共同点来保证另一个结构。虽然这是一个具体的类,但它实际上从未实例化,而是其他类继承它,因为有许多共同的属性不一定在每个GenericModel
中,但在每个BasicModel
中(例如,我们会说每个BasicModel
都有一个id
属性)。
如果我的某个类继承自BasicModel
ChildModel
,并且我想覆盖DoStuff()
,那么这是允许的,因为ChildModel
继承自BasicModel
继承自GenericModel
的。所以我定义了一个覆盖方法(在ChildModel
中),如下所示:
public override string DoStuff<ChildModel>(IEnumerable<ChildModel> input){
foreach(var data in input){
var foo = data.id;
//Do stuff with foo
}
//Do more stuff
}
问题是Visual Studio将data.id
高亮显示为错误,称data
没有名为id
的属性。我的假设是这是由模板方法的where TType : GenericModel
部分引起的;它会忽略中间BasicModel
,因此我无法访问BasicModel
中定义的属性。
这对我来说很奇怪,因为我说输入必须由ChildModel
组成,根据定义,BasicModel
的子类都有{ {1}}属性。
有没有办法在id
的{{1}}覆盖中访问这些中间类属性,或者我设置继承的方式是不可能的?是否有任何变通方法或变更可以允许使用这些属性?
编辑:从评论和答案中可以看出,我对模板方法存在根本性的误解。我真正要做的是在ChildModel
中定义一个泛型方法,该方法将DoStuff()
作为输入,然后在每个子类中重写,其中覆盖使用GenericModel
代替。显然,我已经定义的结构可能无法实现这一目标。
答案 0 :(得分:2)
public override string DoStuff<ChildModel>(IEnumerable<ChildModel> input) { ... }
不会将DoStuff
专门用于仅使用ChildModel
,而只是将TType
参数重命名为ChildModel
。这相当于
public override string DoStuff<T>(IEnumerable<T> input) { }
这不会编译,因为你还需要在基类的TType
上保留约束。
DoStuff
方法的泛型约束意味着覆盖必须统一处理所有子类型。听起来您希望每个子类都支持GenericModel
的单个特定子类型。在这种情况下,您可以将泛型参数移动到基类,并在每个子类中指定它,例如
public abstract class BaseClass<TType> where TType : GenericModel {
public virtual string DoStuff(IEnumerable<TType> input) { ... }
}
public class SubClass : BaseClass<ChildModel> {
public override string DoStuff(IEnumerable<ChildModel> input) { ... }
}
答案 1 :(得分:1)
嗯,使用当前逻辑ChildModel
类型参数只能是GenericModel
类型,因为无法覆盖泛型类型约束。
因此 - 编译器无法知道我们实际上将可转换的内容传递给BasicModel
,这就是我们无法看到属性'id'的原因。
要将其用作BasicModel
,我们可以使用LINQ
投射整个集合:
class GenericModel
{
public virtual string DoStuff<TType>(IEnumerable<TType> input)
where TType : GenericModel
{
return null;
}
}
class BasicModel : GenericModel
{
public int id { get; set; }
}
class ChildModel : BasicModel
{
public override string DoStuff<TType>(IEnumerable<TType> input)
{
var castedInput = input.Cast<BasicModel>();
foreach (var data in castedInput)
{
var foo = data.id;
//Do stuff with foo
}
//Do more stuff
return null;
}
}
答案 2 :(得分:1)
如果你不想要CastException(@Fabjan回答),你可以替换它:
componentsSeparatedByString
用这个:
var castedInput = input.Cast<BasicModel>();
foreach (var data in castedInput)
如果您有这个例子:
foreach (var data in input.OfType<BasicModel>())
使用DoStuff:
new ChildModel().DoStuff(new List<GenericModel>
{
new GenericModel(),
new BasicModel{id = 2},
new ChildModel{id = 10},
new BasicModel{id = 15}
});
您的输出将是:
var foo = data.id;
Console.WriteLine(foo);