在基类集合上调用派生方法

5
我有一个名为A的抽象类,还有其他实现A的类(B、C、D、E等)。 我的派生类保存不同类型的值。 我还有一个A对象列表。
    abstract class A { }
    class B : class A
    {
      public int val {get;private set;}
    }
    class C : class A
    {
      public double val {get;private set;}
    }
    class D : class A
    {
      public string val {get;private set;}
    }

    class Program
    {
        static void Main(string[] args)
        {
          List list = new List { new B(), new C(), new D(), new E() };
          // ... 

          foreach (A item in list)
          {
            Console.WriteLine(String.Format("Value is: {0}", item.val);
          }
        }
    }

...其中.val属性不被基类所知。

我该如何获得这种动态行为?我不想在一长串的switch/if语句中使用getType方法。


1
这里继承自A类并不重要 - A没有val,所以子类的val之间没有关系。你可以直接使用object作为基类。如果你正在使用C# 4.0+,我猜你想使用dynamic - Blorgbeard
1
@Blorgbeard 一个小修正。c#4.0 以及 .net 4.0 - Sriram Sakthivel
4个回答

3
如果你只是想获取val的字符串表示形式,我建议在每个子类中重写ToString方法。
public override string ToString()
{
    return val.ToString();
}

无论如何,如果您想要在子类中使用数据,您需要将其表示为基类中具有共同类型的某种类型(例如 object)。您可以像这样实现:
abstract class A 
{
    public abstract object GetValue();
}
class B : class A
{
    public int val {get;private set;}
    public override object GetValue()
    {
        return val;
    }
}

2

试试这个:

using System;
using System.Collections.Generic;

abstract class A
{
    public abstract dynamic Val { get;   set; }

}
class B : A
{
    public override dynamic Val { get;  set; }
}
class C : A
{
    public override dynamic Val { get;  set; }
}
class D : A
{
    public override dynamic Val { get;  set; }
}

class Program
{
    static void Main(string[] args)
    {
        var list = new List<A> { new B(), new C(), new D() };
        // ... 

        foreach (A item in list)
        {
            Console.WriteLine(String.Format("Value is: {0}", item.Val));
        }
    }
}

我其实已经忘记了 C# 中的 dynamic,因为我从来没有声明过 dynamic 的变量,只在 MVC 应用程序中使用 ViewBag。然而,即使使用它也不能完全满足 OP 的要求,因为重载的成员不是强类型的,所以使用它们的代码仍然需要进行类型转换,并且它们不会限制可以分配给它们的内容。但这已经是最接近 OP 要求的方法了。 - jmcilhinney
@jmcilhinney 所以使用对象。 - user1968030
当分配值时,类型在派生类中内部设置。好处是,您可以设置任何类型的值,并且由于基类和派生类中的类型(dynamic)相同,因此“覆盖”是可能的。使用重写的值(get),您可以调用具有多态行为的toString()。 - Omicron

1
 abstract class A { public string val { get; set; } }
class B :  A
{
  public int val {get;private set;}
}
class C :  A
{
  public double val {get;private set;}
}
class D :  A
{
  public string val {get;private set;}
}

class Program
{
    static void Main(string[] args)
    {
        List<object> list = new List<object> { new B(), new C(), new D() };
      // ... 

      foreach (A item in list)
      {
        Console.WriteLine(String.Format("Value is: {0}", item.val));
      }
    }
}

1
如果val不是基类的成员,则无法在该类型的引用上访问它。这三个派生类都可能有名为val的成员,但它们不是同一个成员,因此不能像处理相同成员那样处理它。你可以声明一个通用类,并将其val属性作为通用类型,但然后你就不能创建该类型的列表。基本上,你想做的事情是不可能的。它不是基于继承,也不是基于泛型。听起来很方便,但这是不合逻辑的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接