代码之家  ›  专栏  ›  技术社区  ›  toadfromgrove

使用从GetType()派生的类型,而不使用开关

  •  0
  • toadfromgrove  · 技术社区  · 7 年前

    我正在使用实体框架和LINQ。我想在GridViews的“helper”类中创建一个可重用的方法。

    该方法将根据传递的实体类型返回一个数据源作为实体列表。

    因此GridView1将显示[Entity1],因此调用将如下所示:

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

    注意*如果我应该在方法中以字符串形式传递我想要的实体类型,那么我可以接受建议。我只是不想在这个方法可以返回的大约40种实体类型之间使用切换用例

    可重用方法将很简单,看起来类似于:

    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();
            }
        }
    }
    

    这听起来很愚蠢,但显然我做不到:

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

    但这基本上就是我想要实现的。

    2 回复  |  直到 7 年前
        1
  •  0
  •   John Wu    7 年前

    如果要在编译时绑定该类型,可以将该类型作为泛型参数传递,并使用以下类型的方法:

            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>;
            }
    

    它是如何工作的?我们不知道返回被请求实体的方法的名称,但我们知道返回类型必须是 DbSet<T> . 因此,我们扫描DatabaseContext以查找任何返回该类型的方法,并调用它。这假设只有一个方法具有该返回类型。

    如果您需要真正的运行时绑定(您不能提供 <T> 参数)可以使用这种方法。请注意,返回类型只是一个常规类型 IEnumerable 因为如果在编译时不知道特定的返回类型,则无法获得该类型。你可以把它放回 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;
            }
    

    这是一个完整的例子。注意,我去掉了EF对象,但这个示例仍然可以使用真实的 DbSet DatabaseContext .

    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);
            }
    
        }
    }
    

    输出:

    User Bob
    User Alice
    Transaction 12.34
    Transaction 56.78
    

    Full code on DotNetFiddle

        2
  •  0
  •   toadfromgrove    5 年前

    这种方法并不合理,我最终将GridView的数据源存储在SessionState变量中。避免了每次回发都需要重新查询数据源(如果在重新查询时必须按顺序进行跟踪,可能会变得很乏味。相反,sessionstate变量保持排序顺序)