2009-08-07 16 views
1

Ich hatte eine kurze Frage. Etwas scheint mit diesem Code wirklich falsch zu sein. Ich möchte die Vorteile von Generika und Delegaten und möglicherweise auch von generischen Delegaten nutzen. Ich arbeite mit einigen Code-generierten APIs und die generierten Objekte sind sehr ähnlich. Ich sehe, dass sie alle eine Schnittstelle implementieren, also sollte ich versuchen, eine Klasse mit ein paar Methoden zu erstellen, um die verschiedenen Szenarien zu behandeln. Hier ist ein Beispielcode. Es fühlt sich einfach auf vielen Ebenen falsch an. Bitte sag mir, wie ich diesen Code verbessern kann. Ein kleiner Refactoring-Tipp, wenn du willst. Und reiße es auf jeden Fall in Stücke. Ich möchte besser programmieren und lernen, Dinge richtig zu machen.Weisen Sie einen Delegaten basierend auf einem Typ zu?

private delegate IsomeEntity DisplayDelegate(IsomeEntity display); 

public IsomeEntity Display<T>() 
{ 
    DisplayDelegate _del = null; 
    IsomeEntity display = factory.CreateObject(typeof(T).Name); 

    if (display.GetType() == typeof(ADisplayEntity)) 
     _del = ADisplayEntity; 

    if (display.GetType() == typeof(BDisplayEntity)) 
     _del = BDisplayEntity; 

    if (display.GetType() == typeof(CDisplayEntity)) 
     _del = CDisplayEntity; 


    return _del(display); 
} 

public ADisplayEntity ADisplayEntity(IsomeEntity display) 
{ 
    ADisplayEntity ade = display as ADisplayEntity; 

    try 
    { 
     ADisplay o = new ADisplay(); 
     ADisplayEntity response = o.ADisplay(ade); 
     return response; 
    } 
    catch (Exception ex) 
    { 
     Exception newEx; 
     if (someExceptionHandler.HandleException(ex, this, out newEx)) 
      throw newEx; 
    } 

    return null; 
} 

public BDisplayEntity BDisplayEntity(IsomeEntity display) 
{ 
    BDisplayEntity dde = display as BDisplayEntity; 

    try 
    { 
     BDisplay o = new BDisplay(); 
     BDisplayEntity response = o.BDisplay(bde); 
     return response; 
    } 
    catch (Exception ex) 
    { 
     Exception newEx; 
     if (someExceptionHandler.HandleException(ex, this, out newEx)) 
      throw newEx; 
    } 

    return null; 
} 

Antwort

0

Sie können Teilnehmer und Lambda-Funktionen wie die generischen Werte übergeben, so etwas wie diese:

public ISomeEntity Display<T>(Func<T, ISomeEntity> conversion) 
{ 
    IsomeEntity display = factory.CreateObject(typeof(T).Name); 
    return conversion(display); 
} 

diesen Aufruf wäre dann:

var myNewEntity = Display( 
    x => ADisplay.GetADisplay(x as ADisplayEntity)); 

Und so weiter.

Ich bin nicht ganz sicher, was Sie versuchen zu tun - so ist mein Code wahrscheinlich nicht ganz richtig, aber es sollte Ihnen und eine Vorstellung davon geben, wie Sie Lambdas herumreichen können.

Sie können sie sogar in Wörterbüchern speichern und nachschlagen.

+0

Ich glaube, er diesen Code in das Anzeigeverfahren will, so dass er es nicht geben jedes Mal, wenn er eine ISomeEntity will hat – Randolpho

0

Ok, wenn ich dir richtig folge, ADisplayEntity und BDisplayEntity sind beide generierte Klassen, die ziemlich gleich aussehen, oder? Und Sie versuchen, eine Art generische Delegaten-Factory-Methode zu erstellen (die Sie Display<T> aufgerufen haben), die dem Aufrufer ermöglicht, den Typ der Anzeige Entität, die Sie möchten, als eine einzelne Schnittstelle, die Sie erstellt haben, dass die Entitäten implementieren, ja ? Ich nehme an, dass die ADisplay und BDisplay Klassen keine gemeinsame Display() Methode implementieren, weshalb Sie die Anrufe zu ADisplay und BDisplay haben. Hmm ... das sind die gleichen Namen wie die Klasse. Tippfehler? Was Sie aufgelistet haben, wird nicht einmal kompiliert.

Ich denke, ein besseres Beispiel ist erforderlich. Ich weiß, dass Sie versuchen, Ihren Code zu bereinigen, aber vielleicht ist ein echter Code mit Namensänderungen besser. Ich würde gerne sehen, was ADisplay, BDisplay, ADisplayEntity und BDisplayEntity wirklich sind.

Das heißt, wenn die verschiedenen A/BDisplay und A/BDisplayEntity Klassen wirklich so unterschiedlich sind, dass Sie diese Delegate Methoden nicht in einer einzigen Methode konsolidieren können, dann tun Sie ziemlich viel das einzige, was Sie tun können, um Ihr ursprüngliches Ziel zu erreichen.

Vielleicht mit mehr Informationen kann ich eine bessere Antwort liefern, aber ich sehe nicht viel hier zu refactor. Abgesehen von den Namen Ihrer Methoden sind dieselben Namen wie die Klassen, die sie instanziieren, und Ihre Aufrufe einer Methode, die denselben Namen wie die Klasse hat.

0

warum nicht so etwas wie einfach? warum brauchen Sie

public static ISomeEntity DisplayEntity(ISomeEntity display) 
{ 

     ISomeEntity result; 
      if (entity is ADisplayEntity) 
      { 
       ADisplay disp = new ADisplay(); 
       result = disp.ADisplayFunc(); 
      } 
      if(entity is BDisplayEntity) 
      { 
       BDisplay disp = new BDisplay(); 
       result = disp.BDisplayFunc(); 
      } 

    return result; 
} 

Natürlich delegates..etc würde es mehr Sinn machen, wenn Sie Ihre AAnzeige und BDisplay auch eine Schnittstelle folgen, wie IDisplay haben könnte dann nur Sie brauchen zurückkehren IDisplay.Display (ISomeEntity)

zu folgen, dass Sie Ihre Anzeigen wie diese wickeln könnte ..

public interface IDisplay 
{ 
    public ISomeEntity Display(ISomeEntity entity); 
} 

public class AWrappedDisplay: IDisplay 
{ 
    public ISomeEntity Display(ISomeEntity entity) 
    { 
     ADisplay disp = new ADisplay(); 
     return disp.ADisplayFunc(entity); 
    } 

} 

public class BWrappedDisplay : IDisplay 
{ 
    public ISomeEntity Display(ISomeEntity entity) 
    { 
     BDisplay disp = new BDisplay(); 
     return disp.BDisplayFunc(entity); 
    } 

} 

public static IDisplay Factory(Type t) 
     { 
      IDisplay disp = null; 
      if (t == typeof(ADisplayEntity)) 
       disp = new AWrappedDisplay(); 

      if (t == typeof(BDisplayEntity)) 
       disp = new BWrappedDisplay(); 

      return disp; 
     } 

und dann können Sie Ihre DisplayEntity nennen wie diese

public static ISomeEntity DisplayEntity(ISomeEntity display) 
    { 
     IDisplay disp = Factory(display.GetType()); 
     ISomeEntity newDisplayEntity = disp.Display(display); 

     return newDisplayEntity; 
    } 
0

Wenn Sie verallgemeinern wollte Mit diesen Methoden könnten Sie beispielsweise Folgendes tun:

private delegate IsomeEntity DisplayDelegate<T>(IsomeEntity display); 

    public IsomeEntity DisplayMethod<T>() where T : IsomeEntity 
    { 
     DisplayDelegate<T> _del = new DisplayDelegate<T>(DoDisplay<T>); 
     IsomeEntity entity = factory.CreateObject(typeof(T).Name); 

     return _del(entity); 
    } 

    public IsomeEntity DoDisplay<T>(IsomeEntity entity) 
    { 
     try 
     { 
      Display<T> o = new Display<T>(); 
      Entity<T> response = o.Display(entity); 
      return response; 
     } 
     catch (Exception ex) 
     { 
      if (someExceptionHandler.HandleException(ex, this, out newEx)) 
       throw newEx; 
     } 
    } 
In diesem Fall ist der Delegat wirklich nicht erforderlich, und Sie können das DoDisplay direkt aufrufen.

public IsomeEntity DisplayMethod<T>() where T : IsomeEntity 
    {    
     IsomeEntity entity = factory.CreateObject(typeof(T).Name); 

     return DoDisplay<T>(entity); 
    } 

    public IsomeEntity DoDisplay<T>(IsomeEntity entity) 
    { 
     try 
     { 
      Display<T> o = new Display<T>(); 
      Entity<T> response = o.Display(entity); 
      return response; 
     } 
     catch (Exception ex) 
     { 
      if (someExceptionHandler.HandleException(ex, this, out newEx)) 
       throw newEx; 
     } 
    } 
+1

ich sehe, was machst du hier aber Ihr Beispiel würde nicht kompilieren, welche Art genau * o *, und wie hat * o * * o.Display (entity) * –

+0

Ich basierte das Beispiel auf dem OP, und das OP hatte "ADisplay" und "BDisplay". Ich habe es gerade in "Display" umbenannt, da es generisch war. Das Beispiel ist für Syntax und Design, es enthält nicht alles, was zum Kompilieren, Erstellen und Ausführen erforderlich ist. Die Details der Implementierung sind dem Benutzer überlassen. –

0

Ich gehe davon aus, da Sie das Zeug erwähnt wurde automatisch generiert, dass ISomeEntity Modifizierung aus dem Fenster ist (sonst würde ich vorschlagen, eine Anzeige() -Methode ISomeEntity Hinzufügen und dann ruft sie direkt auf das Unternehmen über die Schnittstelle Jede Entität würde ihre eigene Version von Display() implementieren.

Also, wenn ich verstehe, was Ihr Code versucht, richtig zu machen (es ist nicht wirklich klar), würde ich vorschlagen, eine IDisplay-Schnittstelle zu erstellen, mit ADisplay und BDisplay erben davon. Diese Schnittstelle hätte eine Methode Display(), die ISomeEntity übernimmt und ISomeEntity zurückgibt. Wenn ADisplay.Display (ISomeEntity) eine BDisplayEntity empfängt, würden Sie jedoch eine Ausnahme auslösen.

Dann würde ich ein IDictionary erstellen, das Sie als ein Feld in der Klasse speichern würden, die diese Anzeige-Methode hat (ich werde es Displayer nennen). Dieses Wörterbuch würde das für jeden Typ zu verwendende IDisplay speichern (dh typeof (ADisplayEntity) -> new ADisplay()).

Sie könnten dann Ihre Display-Hauptmethode zu Displayer hinzufügen, aber jetzt wird ein generisches T zurückgegeben, da T der Typ ist, den Sie erstellen und zurückgeben. Diese Methode sucht nach dem benötigten IDisplay und verwendet es in der Factory-erstellten ISomeEntity, deren Ergebnis zurückgegeben wird.

Die Verwendung des Dictionary bedeutet, dass Sie keine beschissene Menge von if-Anweisungen erhalten und dass Sie einfach mehr IDisplays hinzufügen können, indem Sie einfach zum Wörterbuch hinzufügen.

Hier ist mein Code, der in VS2008 kompiliert.

public interface ISomeEntity 
{ 

} 

public class EntityFactory 
{ 
    public ISomeEntity CreateObject(string name) 
    { 
     //Do factory stuff here 
     return null; 
    } 
} 

public class ADisplayEntity : ISomeEntity 
{ 
} 



public class BDisplayEntity : ISomeEntity 
{ 
} 

public interface IDisplay 
{ 
    ISomeEntity Display(ISomeEntity entity); 
} 

public class ADisplay : IDisplay 
{ 
    public ISomeEntity Display(ISomeEntity entity) 
    { 
     ADisplayEntity aEntity = entity as ADisplayEntity; 
     if (aEntity == null) 
      throw new ArgumentException("Wrong type"); 

     //Do whatever happens when you convert parameter entity into a 
     //"response" ADisplayEntity. I'm just returning a new 
     //ADisplayEntity to make it compile for me 
     return new ADisplayEntity(); 
    } 
} 

public class BDisplay : IDisplay 
{ 
    public ISomeEntity Display(ISomeEntity entity) 
    { 
     BDisplayEntity bEntity = entity as BDisplayEntity; 
     if (bEntity == null) 
      throw new ArgumentException("Wrong type"); 

     //Do whatever happens when you convert parameter entity into a 
     //"response" BDisplayEntity. I'm just returning a new 
     //BDisplayEntity to make it compile for me 
     return new BDisplayEntity(); 
    } 
} 



public class Displayer 
{ 
    private IDictionary<Type, IDisplay> displayers; 
    private EntityFactory factory; 


    public Displayer() 
    { 
     factory = new EntityFactory(); 
     displayers = new Dictionary<Type, IDisplay> 
         { 
          { typeof(ADisplayEntity), new ADisplay() }, 
          { typeof(BDisplayEntity), new BDisplay() } 
         }; 
    } 


    public T Display<T>() where T : class, ISomeEntity 
    { 
     T entity = factory.CreateObject((typeof(T).Name)) as T; //Type-safe because of the factory 
     IDisplay displayer = displayers[typeof(T)]; 
     return displayer.Display(entity) as T; //Typesafe thanks to each IDisplay returning the correct type 
    } 
} 
Verwandte Themen