2012-04-16 18 views
8

Supongamos que tengo dos clases:moldeada ejemplo a base de clase derivada (abatido) en C#

class Employee 

y

class AdvancedEmployee:Employee 

sé que algo como esto no va a funcionar, ya que no puedo abatido en C#:

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

Mi pregunta es: ¿Cómo lograr un downcast de manera eficiente? En realidad tengo un constructor en AdvancedEmployee que toma un Employee como parámetro y lo usa para inyectar sus valores, básicamente haciendo un clon.


actualización

Para solucionar los datos que conseguirían duplicado he cambiado el enfoque un poco y ahora AdvancedEmployee contiene un empleado en lugar de ser uno mismo. Ejemplo:

class Employee; 

class AdvancedEmployee 
{ 
    private employee 

    public AdvancedEmployee(Employee employee){ 

    this.employee = employee 

    }   

} 
+2

¿Ambos se ajustan a una interfaz, IEmployee? – SpaceBison

+0

No puedo modificar Employee. –

+0

@IsraelLot, ciertamente puedes abatir en C#. Sospecho que solo le falta la sintaxis: 'empleado AdvancedEmployee advanced = (AdvancedEmployee);' Por supuesto, esto dará un error en tiempo de ejecución si el objeto al que se hace referencia no es en realidad una instancia de AdvancedEmployee. – Ben

Respuesta

3

No puede ser un molde , en realidad es una conversión entre los diferentes tipos.

Agregaría una función de miembro estático o de ctor como AdvancedEmployee FromBase(Employee e), a constructo tipo derivado del tipo base dado.

+0

@downvoter: ¿me importa explicarlo? – Tigran

1

as en las comprobaciones de C# para el tipo de tiempo de ejecución . Es decir, si el objeto que se está probando no es realmente un AdvancedEmployee, no lo convertirá mágicamente Employee en AdvancedEmployee. Entonces, si necesita un AdvancedEmployee, necesita construirlo usted mismo de alguna manera.

Existen diferentes enfoques dependiendo de lo que va a lograr. Tal vez puede hacerlo con un constructor AdvancedEmployee(Employee proto), que copiará los valores necesarios del proto? O tal vez necesite envolver el Employee existente con un AdvancedEmployee.

Tenga en cuenta que es posible que deba dejar que el código que almacena al empleado anterior lo reemplace con el AdvancedEmployee recién creado.

Un camino a seguir (con cierto gusto de Java) podría ser crear una fábrica de Employee, que crearía un AdvancedEmployee si fuera necesario. Luego debe hacer que todo el código use la fábrica en lugar de crear un Employee con new. Sin embargo, este escenario no sería útil si de todos modos necesita cambiar su tipo de tiempo de ejecución.

+0

Eso es lo que estoy haciendo en este momento. Me preguntaba si había una manera elegante. –

+2

No realmente. Hay otros lenguajes OO donde puede cambiar el _runtime type_ de un objeto sobre la marcha, pero no en C#/Java/C++. en C#, solo puedes crear un _nuevo objeto. – Vlad

+0

@downvoter: ¿me importa explicarlo? – Vlad

2

Crear un nuevo objeto es la forma más legible y más clara. También puede definir operadores de conversión de tipo explícitos o implícitos en su clase Empleado.

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

y luego usarlo como esto:

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

Como OP no puede modificar 'Employee', tampoco puede definir operadores de conversión de tipo explícitos o implícitos dentro de él. – comecme

4

crear una interfaz.Y puesto que no se puede modificar Empleado, crear una adapter que posee:

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

class AdvancedEmployee : IEmployee { } 
+0

@downvoter: ¿me importa explicarlo? –

+0

La votación negativa es mi culpa. Leí mal la pregunta. Lamentablemente, algunos errores implican que no puedo revertir mi voto ahora que me doy cuenta de que estaba equivocado. – Ben

+1

Resulta que si edita la publicación (incluso si agrega un espacio), puede revertir su voto. – Ben

2

Aquí es una forma en que he manejado en el pasado, que me pareció un poco frío ... si todos los elementos de datos en Empleado y AdvancedEmployee son Propiedades, luego puede usar reflection para copiar los valores de datos de la clase base en la clase derivada. Luego puede trabajar con la clase derivada como si originalmente se hubiera escrito de esa manera sin tener que encapsular la clase base.

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)); 
Cuestiones relacionadas