2017-11-13 2 views
0

Ich benutze Entity Framework und LINQ. Ich möchte eine wiederverwendbare Methode in einer "Helfer" -Klasse für GridViews erstellen.Benutze Typ abgeleitet von GetType() ohne Verwendung von Switch

Die Methode gibt eine DataSource als eine Liste von Entitäten zurück, die auf dem Typ der übergebenen Entität basieren.

So GridView1 zeigen [Entity1] 's so der Aufruf wie folgt aussehen wird:

GridView1.DataSource = helperClass.GetDataSource(new Entity1()); 

Hinweis * Wenn ich den Entitätstyp passieren sollte ich als String wollen in der Methode, die ich für Anregung offen bin. Ich will nur nicht, diese Methode

einen Schalter Fall zwischen den ~ 40 Entity-Typen zu verwenden, haben

Die wiederverwendbare Methode ist einfach und ähnlich aussehen wird zurückkehren könnte:

public static object GetDataSource(object type) 
{ 
    using (DatabaseContext dc = new DatabaseContext()) 
    { 
     if (dc.[how do I get the entity type here].Count() > 0) 
     { 
      var modelList = dc.[how do I get the entity type here also].ToList(); 
     } 
    } 
} 

Das klingt albern, aber offensichtlich war ich nicht in der Lage zu tun:

var modelList = dc.(type.GetType()).ToList(); 

aber das ist im Grunde, was ich erreichen möchte.

+0

Was nützt das tun Sie? Sie erhalten eine Liste von Objekten zurück, wissen aber ihren Typ zur Kompilierzeit nicht? Ich vermute, dass es einen besseren Weg gibt, mit Generika zu tun, was man will. –

+0

Das heißt, das ist in der Nähe eines Duplikats von https://StackOverflow.com/Questions/1919632, mit dem Unterschied, dass Sie den Namen von dem Typ zuerst erhalten müssen. –

+0

@DStanley Dort kann sehr gut sein. Dies war nur der erste Ansatz, an den ich dachte, als ich versuchte, eine wiederverwendbare Hilfsmethode zu erstellen. Ich habe eine Webanwendung mit mehreren GridViews mit ähnlichen Methoden (wie sort, bind und databound), also wollte ich für diese Methoden wiederverwendbare Methoden in einer Remote-Klasse machen, anstatt denselben Code einzugeben (mit der Varianz dessen, für was Entität gezeigt wird) die GridView) ~ 40 mal – toadfromgrove

Antwort

0

Wenn Sie die Art zum Zeitpunkt der Kompilierung binden möchten, können Sie den Typ als generisches Argument übergeben, und diese Art der Methode:

 public DbSet<T> GetDataSource<T>() 
     { 
      var targetType = typeof(DbSet<T>); 

      return _db 
       .GetType() 
       .GetMethods() 
       .Where(m => m.ReturnType == targetType) 
       .Single() 
       .Invoke(_db, null) as DbSet<T>; 
     } 

Wie funktioniert es? Nun, wir kennen den Namen der Methode nicht, die die Entität zurückgibt, die angefordert wird, aber wir wissen, dass der Rückgabetyp eine DbSet<T> sein muss. Also scannen wir den DatabaseContext nach jeder Methode, die diesen Typ zurückgibt, und rufen sie auf. Dies setzt voraus, dass es genau eine Methode gibt, die diesen Rückgabetyp hat.

Wenn Sie eine echte Laufzeitbindung benötigen (Sie können den Parameter <T> nicht angeben), können Sie diese Methode verwenden. Beachten Sie, dass der Rückgabetyp nur eine allgemeine IEnumerable ist, da Sie keinen bestimmten Rückgabetyp haben können, wenn er zur Kompilierungszeit nicht bekannt ist. Sie können sie bei Bedarf jederzeit wieder an DbSet<T> übertragen.

 public IEnumerable GetDataSource(Type type) 
     { 
      var targetType = typeof(DbSet<>).MakeGenericType(new Type[] { type }); 

      return _db 
       .GetType() 
       .GetMethods() 
       .Where(m => m.ReturnType == targetType) 
       .Single() 
       .Invoke(_db, null) as IEnumerable; 
     } 

Hier ist ein vollständiges Beispiel. Beachten Sie, dass ich die EF-Objekte ausgedruckt habe, aber dieses Beispiel sollte immer noch mit einem echten DbSet und DatabaseContext funktionieren.

using System; 
using System.Linq; 
using System.Collections; 
using System.Collections.Generic; 

public class Program 
{ 

    public class DbSet<T> : List<T> 
    { 
    } 

    public class User 
    { 
     public string Name { get; set; } 
     public override string ToString() 
     { 
      return "User " + Name; 
     } 
    } 

    public class Transaction 
    { 
     public decimal Amount { get; set; } 
     public override string ToString() 
     { 
      return "Transaction " + Amount.ToString("0.00"); 
     } 
    } 

    public class DatabaseContext 
    { 
     public DbSet<User> GetUsers() 
     { 
      return new DbSet<User>() 
      { 
       new User { Name = "Bob" }, 
       new User { Name = "Alice" } 
      }; 
     } 
     public DbSet<Transaction> GetTransactions() 
     { 
      return new DbSet<Transaction>() 
      { 
       new Transaction { Amount = 12.34M }, 
       new Transaction { Amount = 56.78M } 
      }; 
     } 

    } 

    public class HelperClass 
    { 
     private readonly DatabaseContext _db; 

     public HelperClass(DatabaseContext db) 
     { 
      _db = db; 
     } 

     public DbSet<T> GetDataSource<T>() 
     { 
      var targetType = typeof(DbSet<T>); 

      return _db 
       .GetType() 
       .GetMethods() 
       .Where(m => m.ReturnType == targetType) 
       .Single() 
       .Invoke(_db, null) as DbSet<T>; 
     } 

     public IEnumerable GetDataSource(Type type) 
     { 
      var targetType = typeof(DbSet<>).MakeGenericType(new Type[] { type }); 

      return _db 
       .GetType() 
       .GetMethods() 
       .Where(m => m.ReturnType == targetType) 
       .Single() 
       .Invoke(_db, null) as IEnumerable; 
     } 
    } 

    public static void Main() 
    { 
     var helperClass = new HelperClass(new DatabaseContext()); 

     foreach (var u in helperClass.GetDataSource<User>()) 
     { 
      Console.WriteLine(u); 
     } 

     foreach (var t in helperClass.GetDataSource(typeof(Transaction))) 
     { 
      Console.WriteLine(t); 
     } 

    } 
} 

Ausgang:

User Bob 
User Alice 
Transaction 12.34 
Transaction 56.78 

Full code on DotNetFiddle

Verwandte Themen