2012-04-16 11 views
8

Załóżmy, że mam dwie klasy:instancja podstawa do klasy pochodnej (przygnębiony) w C#

class Employee 

i

class AdvancedEmployee:Employee 

wiem, coś takiego nie będzie działać, ponieważ nie mogę downcast na C#:

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

Moje pytanie brzmi: jak osiągnąć downcast w efektywny sposób? W rzeczywistości mam konstruktor na AdvancedEmployee, który pobiera pracownika jako parametr i użyć go do wstrzyknięcia jego wartości, w zasadzie tworzenia klonu.


Aktualizacja

Aby rozwiązać te dane, które dostanie kopiowane zmieniłem podejście trochę i teraz AdvancedEmployee ZAWIERA pracownika raczej niż jeden sam. Przykład:

class Employee; 

class AdvancedEmployee 
{ 
    private employee 

    public AdvancedEmployee(Employee employee){ 

    this.employee = employee 

    }   

} 
+2

Czy oba są zgodne z interfejsem, IEmployee? – SpaceBison

+0

Nie mogę zmodyfikować pracownika. –

+0

@IsraelLot, na pewno można downcast w C#. Podejrzewam, że po prostu brakuje ci składni: 'AdvancedEmployee advanced = (AdvancedEmployee) employee;' Oczywiście spowoduje to błąd czasu wykonania, jeśli odwoływany obiekt nie jest w rzeczywistości instancją AdvancedEmployee. – Ben

Odpowiedz

3

To nie może być obsada, to faktycznie konwersja między różnymi rodzajami.

Dodałbym funkcję ctor lub funkcję statycznego członka, taką jak AdvancedEmployee FromBase(Employee e), do skonstruować typ pochodny z danego typu bazy.

+0

@downvoter: czy chcesz wyjaśnić? – Tigran

1

as w testach C# dla typu runtime typu. Oznacza to, że jeśli testowany obiekt nie jest w rzeczywistości AdvancedEmployee, nie można go przekonwertować w sposób magiczny na Employee na AdvancedEmployee. Więc jeśli potrzebujesz AdvancedEmployee, musisz to jakoś skonstruować.

Istnieją różne podejścia w zależności od tego, co zamierzasz osiągnąć. Być może możesz zrobić z konstruktorem AdvancedEmployee(Employee proto), który skopiuje potrzebne wartości z proto? A może potrzebujesz owinąć istniejący Employee z AdvancedEmployee.

Należy pamiętać, że może zaistnieć potrzeba, aby kod, który przechowuje stary pracownik, zastąpił nowo utworzonym AdvancedEmployee.

Jedną z metod (z odrobiną smaku Java) może być stworzenie fabryki Employee, która w razie potrzeby utworzy AdvancedEmployee. Następnie musisz wykonać cały kod z fabryki, zamiast tworzyć Employee z new. Ten scenariusz nie pomógłby jednak, gdyby i tak trzeba było zmienić typ środowiska wykonawczego.

+0

Właśnie to robię teraz. Zastanawiałem się, czy istnieje jakiś wymyślny sposób. –

+2

Niezupełnie. Istnieją inne języki, w których można zmienić _runtime type_ obiektu w locie - ale nie w C#/Java/C++. w języku C# można utworzyć tylko _new_ obiekt. – Vlad

+0

@downvoter: czy chcesz wyjaśnić? – Vlad

2

Tworzenie nowego obiektu jest najbardziej czytelnym i najczystszym sposobem. Można również zdefiniować jawne lub niejawne operatory konwersji typów w klasie Pracownik.

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

a następnie używać go tak:

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

Ponieważ OP nie może modyfikować "pracownika", nie może również zdefiniować jawnych lub niejawnych operatorów konwersji typów wewnątrz niego. – comecme

4

Załóż interfejs.A ponieważ nie można modyfikować pracownikiem, tworzyć adapter że jesteś właścicielem:

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

class AdvancedEmployee : IEmployee { } 
+0

@downvoter: czy chcesz wyjaśnić? –

+0

Spadek jest moją winą. Zły odczytałem pytanie. Niestety niektóre pomyłki oznaczają, że nie mogę powrócić do mojego głosu, teraz zdaję sobie sprawę, że się pomyliłem. – Ben

+1

Okazuje się, że jeśli edytujesz wpis (nawet dodając pojedyncze miejsce), możesz przywrócić swój głos. – Ben

2

Oto sposób mam obchodzić go w przeszłości, które uważałem za fajne ... jeśli wszystkie elementy danych w Pracownika i AdvancedEmployee są właściwościami, następnie można użyć odbicia, aby skopiować wartości danych z klasy bazowej do klasy pochodnej. Następnie możesz pracować z klasą pochodną tak, jakby został pierwotnie wpisany w ten sposób bez konieczności hermetyzacji klasy podstawowej.

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)); 
Powiązane problemy