使用从 GetType() 派生的类型而不使用 Switch

Use type derived from GetType() without using Switch

我正在使用 Entity Framework 和 LINQ。我想在 "helper" class 中为 GridView 创建一个可重用的方法。

该方法将 return 数据源作为实体列表,基于传递的实体类型。

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

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

注意* 如果我应该在我公开征求建议的方法中将我想要的实体类型作为字符串传递。我只是不想在这种方法可以 return

的 ~40 种实体类型之间使用 switch case

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

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

但这基本上就是我想要完成的。

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

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

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

如果你需要真正的运行时间绑定(你不能提供<T>参数)你可以使用这种方法。请注意,return 类型只是一个通用的 IEnumerable 类型,因为如果在编译时不知道特定的 return 类型,则不能使用它。如果需要,您可以随时将其转换回 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 对象,但此示例仍应使用真实的 DbSetDatabaseContext.

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

这种方法不太合理,我最终将 GridView 的数据源存储在 SessionState 变量中。节省了每次回发都必须重新查询 DataSource 的麻烦(如果我在重新查询时必须跟踪顺序,可能会变得乏味。相反,sessionstate 变量保持排序顺序)