【问题标题】:Use type derived from GetType() without using Switch使用从 GetType() 派生的类型而不使用 Switch
【发布时间】:2017-11-13 21:21:54
【问题描述】:

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

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

所以 GridView1 将显示 [Entity1] 的,所以调用看起来像:

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

注意* 如果我应该在方法中将我想要的实体类型作为字符串传递,我愿意接受建议。我只是不想在此方法可能返回的约 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();

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

【问题讨论】:

  • 这对你有什么好处?你得到一个对象列表,但在编译时不知道它们的类型?我怀疑有一种更好的方法可以用泛型做你想做的事情。
  • 也就是说,这与stackoverflow.com/questions/1919632 的副本很接近,不同之处在于您需要先从类型中获取名称。
  • @DStanley 很有可能。这只是我在尝试制作可重用的辅助方法时想到的第一种方法。我有一个带有多个 GridView 的 Web 应用程序,这些 GridView 具有相似的方法(如排序、绑定和数据绑定),所以我想在远程类中为这些方法创建可重用的方法,而不是键入相同的代码(显示的实体有所不同) GridView) ~40 次
  • 检查重复项,它使用字符串而不是类型,而是使用反射来“找到”对应的属性。它不优雅并且破坏了类型安全,但会做你想做的事。

标签: c# entity-framework linq gridview reusability


【解决方案1】:

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

        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&lt;T&gt;。因此,我们扫描 DatabaseContext 以查找任何返回该类型的方法,然后调用它。这假定只有一种方法具有该返回类型。

如果您需要真正的运行时绑定(您不能提供&lt;T&gt; 参数),您可以使用这种方法。请注意,返回类型只是一般的IEnumerable,因为如果在编译时不知道,则不能有特定的返回类型。如果需要,您可以随时将其转换回 DbSet&lt;T&gt;

        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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-03
      • 2016-09-17
      • 2012-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-13
      相关资源
      最近更新 更多