2009-04-29 19 views
5

Bellow jest uproszczona wersja kodu mam:Generic problemem fabryka klasa

public interface IControl<T> 
{ 
    T Value { get; } 
} 

public class BoolControl : IControl<bool> 
{ 
    public bool Value 
    { 
     get { return true; } 
    } 
} 

public class StringControl : IControl<string> 
{ 
    public string Value 
    { 
     get { return ""; } 
    } 
} 
public class ControlFactory 
{ 
    public IControl GetControl(string controlType) 
    { 
     switch (controlType) 
     { 
      case "Bool": 
       return new BoolControl(); 
      case "String": 
       return new StringControl(); 
     } 
     return null; 
    } 
} 

Problem polega na sposobie GetControl z ControlFactory klasie. Ponieważ zwraca IControl i mam tylko IControl < T> to ogólny interfejs. Nie mogę podać T, ponieważ w przypadku Boola będzie to bool, aw przypadku String będzie to ciąg.

Każdy pomysł, co muszę zrobić, aby działało?

Odpowiedz

5

Po prostu wypisz IControl<T> z IControl.

public interface IControl<T> : IControl 
{ 
    T Value { get; } 
} 

UPDATE

Gdybym missunterstood, a ty nie chcesz nierodzajową interfejs, trzeba będzie dokonać metoda GetControl() rodzajowy, too.

public IControl<T> GetControl<T>() 
{ 
    if (typeof(T) == typeof(Boolean)) 
    { 
     return new BoolControl(); // Will not compile. 
    } 
    else if (typeof(T) == typeof(String)) 
    { 
     return new StringControl(); // Will not compile. 
    } 
    else 
    { 
     return null; 
    } 
} 

Teraz masz problem, że nowe kontrole nie można niejawnie rzutować na IControl<T> i trzeba by zrobić to jednoznaczne.

public IControl<T> GetControl<T>() 
{ 
    if (typeof(T) == typeof(Boolean)) 
    { 
     return new (IControl<T>)BoolControl(); 
    } 
    else if (typeof(T) == typeof(String)) 
    { 
     return (IControl<T>)new StringControl(); 
    } 
    else 
    { 
     return null; 
    } 
} 

UPDATE

Zmieniono obsadę z as IControl<T> do (IControl<T>). Jest to preferowane, ponieważ spowoduje wystąpienie wyjątku, jeśli wystąpi błąd, podczas gdy as IControl<T> po cichu zwróci null.

3
public IControl<T> GetControl<T>() 
{ 
    switch (typeof(T).Name) 
    { 
     case "Bool": 
      return (IControl<T>) new BoolControl(); 
     case "String": 
      return (IControl<T>) new StringControl(); 
    } 
    return null; 
} 

Aktualizacja; poprawiono kilka błędów w kodzie. Herezje wezwanie, aby uzyskać klasę:

IControl<bool> boolControl = GetControl<bool>(); 
+3

@Vadim - Zdecydowanie radzę skorzystać z rozwiązania Daniela, w którym porównuje typy, zamiast używać ciągów. Używanie nazwy typu jest bardziej podatne na błędy. –

+0

@Jon B: masz rację; porównanie typów zapewni bardziej odporny kod. Po prostu zaktualizowałem oryginalny kod Vadima do pracy. Podejście Daniela jest lepszą drogą. –

0

typu Zwrot musi mieć charakter ogólny, ponieważ, dobrze, że jest. Pomyśl, jak byś tego użył. Zwrócenie mocno napisanego obiektu eliminuje potrzebę zastosowania ogólnej metody fabrycznej.

Nawet jeśli można zrobić to, co jest zysk

IControl<bool> boolControl = controlFactory.GetControl("bool"); 

lub ten, który będzie działać,

IControl<bool> boolControl = controlFactory.GetControl<bool>("bool"); 

w określonym

IControl<bool> boolControl = controlFactory.GetBoolControl("bool"); 

Tak czy inaczej, masz przełącznik() po stronie klienta. Zwróć obiekt lub korzystaj z niepisanego interfejsu IControl.