繁体   English   中英

在foreach循环中使用基类时调用派生类方法

[英]Call derived class method when using base class in foreach loop

我有以下代码,它们仅循环遍历EdiElements列表并验证每个EdiElements以确保其符合一组定义为派生类的属性的规则。

我遇到的问题是elem.Validate()行,它正在调用基类方法而不是派生类方法。 _elements列表包含所有都从EdiElement派生的不同类,我需要能够遍历所有这些类并在每个这些类中执行验证规则。

在下例中将基类用作foreach循环中的迭代器变量时,在派生类上调用方法的标准方法是什么?

public override bool Validate()
{
  foreach ( EdiElement elem in _elements )
  {
    if ( !_checkElementIsValid( this, elem ) )
      base.ValidationErrors.Add( string.Format( "Element {0} does not belong to segment {1}", this.GetType().Name, this.GetType().Name ) );
    else
      elem.Validate(); // <-- I want this to call derived class method
  }

  return base.ValidationErrors.Count == 0;
}

编辑以显示类定义。

public abstract class EdiElement : Edi
{
  public override bool Validate()
  {
    return true; // breakpoint here gets hit
  }
}

public abstract class EdiDataElement<T> : EdiElement
{
  public T Value { get; set; }
}

public class E3286 : EdiDataElement<String>
{
  public override bool Validate()
  {
    return base.Validate(); // breakpoint here does not get hit!
  }
}

我忘了添加基类。

public abstract class Edi
{
    protected static List<string> _validationErrors = new List<string>();

    public List<string> ValidationErrors
    {
        get
        {
            return _validationErrors;
        }
    }

    public abstract bool Validate();
}

在更改EdiElement之后,我设法解决了它,以便它在Validate()方法中定义了一个abstract override ,然后在派生类中覆盖了它。 现在,代码可以按照我期望的方式正确执行。

public override bool Validate()
{
  foreach ( EdiElement elem in _elements )
  {
    if ( !_checkElementIsValid( this, elem ) )
      base.ValidationErrors.Add( string.Format( "Element {0} does not belong to segment {1}", this.GetType().Name, this.GetType().Name ) );
    else
      elem.Validate(); // <-- I want this to call derived class method
  }

  return base.ValidationErrors.Count == 0;
}

public abstract class EdiElement : Edi
{
  public abstract override bool Validate();
}

public abstract class EdiDataElement<T> : EdiElement
{
  public T Value { get; set; }
}

/// <summary>
///  To specify a component of an address.
/// </summary>
[DataElementMetadata(
    Name = "Address component",
    Description = "To specify a component of an address.",
    Type = Types.Type.an,
    Length = "0..70" )]
public class E3286 : EdiDataElement<String>
{
    public override bool Validate()
    {
        base.ValidationErrors.Add( "Validation error!" );
        return false;
    }
}

我要感谢社区为我指明了正确的方向,因为我确定自己做错了什么。

我认为正在发生的事情是以某种方式(尽管进行了调试构建和设置),编译器正在优化对base.Validate()的调用,这就是为什么未命中断点的原因。

以下内容(按照原始的班级设计)对我来说是正确的:

A x = new D();
x.Test();

public abstract class A
{
    public abstract void Test();
}

public abstract class B : A
{
    public override void Test()
    {
        Console.WriteLine("Test() in B");
    }
}

public abstract class C<T> : B
{

}

public class D : C<String>
{
    public override void Test()
    {
        base.Test(); //breakpoint hits here
    }
}

那是... C#的特殊之处。

如果定义了一个基类并从其继承,则默认行为是,当实例被转换为基类时,被覆盖的方法将还原为被覆盖方法的基类实现,除非该覆盖被关键字override显式标记。 。

如果您问我,这违反了OO编程的基本原则(如果您将狗称为动物,那么它就不会停止成为狗)。 就个人而言,我认为在决定这种行为时,C#的设计师感到很沮丧,但我离题了。

例如,该程序:

class Animal         { public virtual  void Speak() { Console.WriteLine("Most animals make some sort of noise.") ; } }
class Dog : Animal   { public virtual  void Speak() { Console.WriteLine("Dog: Woof!") ; } }
class Cat : Animal   { public new      void Speak() { Console.WriteLine("Meow!") ; } }
class Sheep : Animal { public override void Speak() { Console.WriteLine("Baaa!") ; } }

static void Main( string[] args )
{
  Animal[] menagerie = { new Animal() , new Dog() , new Cat() , new Sheep() , } ;

  foreach ( Animal creature in menagerie )
  {
    Console.Write( "{0}:\t" , creature.GetType().Name ) ;
    creature.Speak() ;
  }

  return;
}

产生以下输出:

Animal: Most animals make some sort of noise.
Dog:    Most animals make some sort of noise.
Cat:    Most animals make some sort of noise.
Sheep:  Baaa!

此功能意味着,在C#程序中,要获得人们通常期望的行为,需要开发人员进行额外的工作。 除非另外有特殊要求,否则最好始终使用abstract / virtualoverride

暂无
暂无

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

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