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

时间:2014-06-25 18:38:04

标签: c#

我有以下代码,它只是循环遍历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();
}

3 个答案:

答案 0 :(得分:1)

我在更改EdiElement后设法解决了这个问题,以便在abstract override方法中定义Validate(),然后在派生类中重写它。代码现在正以我期望的方式正确执行。

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

我要感谢社区指出我正确的方向,因为我确信我做错了。

答案 1 :(得分:0)

我认为正在发生的事情是(尽管调试构建和设置),编译器正在优化对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
    }
}

答案 2 :(得分:-2)

这是...... C#的特殊性。

如果定义基类并从中继承,则默认行为是,当实例向上基类转换时,重写方法将恢复为重写方法的基类实现,除非重写明确标记为关键字override

如果你问我,这违反了O-O编程的基本原则(如果你将它称为动物,狗就不会停止成为狗)。就个人而言,我认为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是一种很好的做法。