【问题标题】:Cast base instance to derived class (downcast) in C#在 C# 中将基实例转换为派生类(向下转换)
【发布时间】:2012-04-16 10:53:50
【问题描述】:

假设我有两个类:

class Employee 

class AdvancedEmployee:Employee

我知道这样的事情是行不通的,因为我不能在 C# 上沮丧:

var employee = new Employee();
var advanced = employee as AdvancedEmployee;

我的问题是:如何以有效的方式完成沮丧? 实际上,我在 AdvancedEmployee 上有一个构造函数,它接受一个 Employee 作为参数并使用它来注入它的值,基本上是进行克隆。


更新

为了解决可能重复的数据,我稍微改变了方法,现在 AdvancedEmployee 包含一名员工,而不是自己。 示例:

class Employee;

class AdvancedEmployee
{
   private employee

   public AdvancedEmployee(Employee employee){

    this.employee = employee

  }           

}

【问题讨论】:

  • 让两者都符合一个接口,IEmployee?
  • 我无法修改员工。
  • @IsraelLot,你当然可以在 C# 中失望。我怀疑您只是缺少语法:AdvancedEmployee advanced = (AdvancedEmployee)employee; 当然,如果引用的对象实际上不是 AdvancedEmployee 的实例,这将产生运行时错误。
  • @Ben:在 Israel 的例子中,employee 显然不是 AdvancedEmployee 的一个实例,而只是一个 Employee。
  • @comecme,是的,我被他使用的“沮丧”这个词误导了。他根本没有贬低,他正在转换为派生类型。

标签: c# downcast


【解决方案1】:

创建一个接口。由于您无法修改 Employee,请创建一个您拥有的 adapter

class EmployeeAdapter : IEmployee
{
    private Employee emp;
    public EmployeeAdapter(Employee emp) { this.emp = emp; }
    public int SomeMethodInEmployee() { return emp.SomeMethodInEmployee(); }
}

class AdvancedEmployee : IEmployee { } 

【讨论】:

  • 投反对票是我的错。我误读了这个问题。不幸的是,一些错误功能意味着我现在意识到我错了,我无法恢复我的投票。
  • 事实证明,如果您编辑帖子(甚至添加一个空格),您就可以恢复您的投票。
【解决方案2】:

不能是cast,实际上是不同类型之间的转换

我会添加一个像AdvancedEmployee FromBase(Employee e) 这样的ctor 或静态成员函数到construct 来自给定基类型的派生类型。

【讨论】:

    【解决方案3】:

    这是我过去处理过的一种方法,我认为这很酷...如果 Employee 和 AdvancedEmployee 中的所有数据元素都是属性,那么您可以使用反射将数据值从基类复制到派生类。然后,您可以使用派生类,就好像他最初是这样键入的,而不必封装基类。

    public class Employee
    {
        public int ID { get; set; }
        public string Foo { get; set; }
    
        public void SomeMethod() { }
    }
    
    public class AdvancedEmployee : Employee
    {
        public string Bar { get; set; }
    
        public void SomeAdvMethod() { }
    }
    
    Employee emp = new Employee() { ID = 5, Foo = "Hello" };
    
    // To create a AdvancedEmployee from emp
    AdvancedEmployee advEmp = new AdvancedEmployee() { Bar = "A prop not in Emp that might need a value" }
    foreach (var p in typeof(Employee).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.CanWrite))
        typeof(AdvancedEmployee).GetProperty(p.Name).SetValue(advEmp, p.GetValue(emp));
    

    【讨论】:

      【解决方案4】:

      创建一个新对象是最易读和最清晰的方法。您还可以在 Employee 类中定义显式或隐式类型转换运算符。

      public static explicit operator AdvancedEmployee(Employee e)
      {
          return new AdvancedEmployee(e);
      }
      

      然后像这样使用它:

      var e = new Employee();
      var ae = (AdvancedEmployee) e;
      

      【讨论】:

      • 由于OP不能修改Employee,他也不能在其中定义显式或隐式类型转换运算符。
      【解决方案5】:

      as 在 C# 中检查 运行时类型。也就是说,如果被测试的对象确实不是AdvancedEmployee,你不会让它神奇地将Employee 转换为AdvancedEmployee。所以如果你需要AdvancedEmployee,你需要自己构建它。

      根据您要实现的目标,有不同的方法。也许您可以使用构造函数AdvancedEmployee(Employee proto),它将从proto 复制所需的值?或者,您可能需要用AdvancedEmployee 包装现有的Employee

      请注意,您可能需要让存储旧员工的代码将其替换为新创建的AdvancedEmployee

      一种可行的方法(带有一些 Java 风格)可能是创建一个 Employee 工厂,如果需要,它将创建一个 AdvancedEmployee。然后你需要让所有代码都使用工厂,而不是用new创建一个Employee。但是,如果您仍然需要更改运行时类型,这种情况将无济于事。

      【讨论】:

      • 这就是我现在正在做的事情。我想知道是否有一种奇特的方式。
      • 并非如此。还有另一种 OO 语言,您可以在其中动态更改对象的运行时类型——但不能在 C#/Java/C++ 中。在 C# 中,您只能创建一个 new 对象。
      • 在我看来,提问者只是想知道如何在 C# 中进行向下转换。
      • @Ben:不是真的。看,OP 创建了一个Employee 的实例,并尝试将其变成AdvancedEmployee。他说他是通过一个构造函数来完成它的Employee,所以问题实际上在于更改运行时类型。
      • @Vlad 不幸的是,一些错误功能意味着我现在无法恢复我的投票。
      猜你喜欢
      • 1970-01-01
      • 2017-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-30
      • 2017-01-08
      • 2013-11-17
      相关资源
      最近更新 更多