繁体   English   中英

在重写模板方法时访问中间类属性

[英]Accessing intermediate class properties in override of template method

我有一个抽象类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 ,而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的属性。 我的假设是这归因于template方法的where TType : GenericModel部分; 它忽略了中间的BasicModel ,因此我无法访问BasicModel定义的BasicModel

这对我来说似乎很奇怪,因为我要说输入必须ChildModel组成,根据定义,所有这些都将作为idBasicModel子类。

有没有一种方法可以在ChildModelDoStuff()重写中访问这些中间类属性,或者用我设置继承的方式是不可能的吗? 我可以进行任何变通办法或更改以允许使用这些属性吗?

编辑:从评论和答案看来,我对模板方法有基本的误解。 我真正想做的是在GenericModel中定义一个通用方法,该方法以IEnumerable<GenericModel>作为输入,然后在每个子类中都将其重写,其中重写使用IEnumerable<ChildClass>代替。 显然,使用我定义的结构可能无法实现该目标。

public override string DoStuff<ChildModel>(IEnumerable<ChildModel> input) { ... }

并不是专门让DoStuff仅与ChildModel一起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) { ... }
}

好吧,使用当前逻辑, ChildModel类型参数只能是GenericModel类型,因为不可能覆盖泛型类型约束。 因此,编译器无法知道我们实际上传递了可转换为BasicModel ,这就是为什么我们看不到属性'id'的原因。

要将其用作BasicModel我们可以使用LINQ BasicModel整个集合:

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;
    }
}

如果您不想要CastException(@Fabjan答案),则可以替换为:

var castedInput = input.Cast<BasicModel>();  
foreach (var data in castedInput) 

有了这个:

foreach (var data in input.OfType<BasicModel>())

这样,如果您有以下示例:

new ChildModel().DoStuff(new List<GenericModel>
{
   new GenericModel(),
   new BasicModel{id = 2},
   new ChildModel{id = 10},
   new BasicModel{id = 15}
});

使用DoStuff像这样:

var foo = data.id;
Console.WriteLine(foo); 

您的输出将是:

2
10
15

暂无
暂无

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

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