.net - 将反射 .GetValue() 对象强转换为通用 DbSet

标签 .net vb.net entity-framework generics reflection

我在 VS 2010 (.Net 4.0) 中使用 EF 4.3.1 从数据库加载许多引用表,以便将它们绑定(bind)到 WinForms 应用程序中的控件。

在表单加载时,我预取数据以便将其存储在本地,并且创建 BindingSource 对象的字典,可使用该字典将本地数据绑定(bind)到控件。目的是最大限度地减少 EF self 验证对冷查询的影响,以便更快地加载表单并提高 UI 响应能力。

我编写了代码来创建和获取给定 DbSet 集合的 BindingSource 对象,如下所示:

Private _dictBindings As New Dictionary(Of String, BindingSource)

Private Sub ValidateBinding(Of T As Class)(ByRef DbCollection As DbSet(Of T))
   Dim strClassName As String = DbCollection.[GetType]().GetGenericArguments(0).Name
   If Not _dictBindings.ContainsKey(strClassName) Then
      _dictBindings.Add(strClassName, New BindingSource With {.DataSource = DbCollection.Local.ToBindingList})
   End If
End Sub

Public Function GetBinding(Of T As Class)(ByRef DbCollection As DbSet(Of T)) As BindingSource
   ValidateBinding(Of T)(DbCollection)
   Return _dictBindings(DbCollection.[GetType]().GetGenericArguments(0).Name)
End Function

这段代码有效,我可以调用

ValidateBinding(Db.ProvinceStates)

ComboBox1.DataSource = GetBinding(Db.Cities)

但是,我想在启动时对模型中的所有 DbSet 集合调用 ValidateBinding,并且我想使用反射来迭代上下文中的可用集合,因为我们当前正在加载 66 个表,并且可以添加稍后再说。

我编写了以下代码:

For Each propSet As PropertyInfo In Db.GetType.GetProperties(BindingFlags.Instance Or BindingFlags.Public).Where(Function(P) P.PropertyType.IsGenericType)
    ValidateBinding(propSet.GetValue(Db, Nothing))
Next

...但它不会工作,因为 propSet.GetValue() 返回一个对象而不是 DbSet(of T)。我也无法将对象转换为适当类型的 DbSet,即使我通过反射知道该类型。

我无权访问 C# 动态类型,并且我知道将泛型与反射混合起来很痛苦,但是是否有一种解决方案可以将反射的 DbSet 传递给我的函数?也许使用 Method.Invoke 的东西?

最佳答案

我想我已经解决了这个问题,解决方案是使用 Method.Invoke。

首先,我将函数转换为扩展方法。虽然这不是必需的,但它确实允许我编写:

db.ProvinceStates.ValidateBinding

ComboBox1.DataSource = db.Cities.GetBinding

其次,我使用 GetMethod、MakeGenericMethod 和 Invoke 编写以下内容:

Dim methodLoad = GetType(DbExtensions).GetMethod("Load", BindingFlags.Static Or BindingFlags.Public)

For Each propSet As PropertyInfo In Db.GetType.GetProperties(BindingFlags.Instance Or BindingFlags.Public).Where(Function(P) P.PropertyType.IsGenericType)
   Dim oSet As Object = propSet.GetValue(Db, Nothing)
   methodLoad.Invoke(Nothing, {oSet})

   Dim methodValidateBinding = GetType(DbSetExtender).GetMethod("ValidateBinding", BindingFlags.Static Or BindingFlags.Public).MakeGenericMethod(propSet.PropertyType.GetGenericArguments(0))
   If methodValidateBinding IsNot Nothing Then
      methodValidateBinding.Invoke(Nothing, {oSet})
   End If
Next

这会一石二鸟,加载所有 66 个表的数据,并创建它们的 BindingSource 对象来绑定(bind)控件。 (DbSetExtender 是我自己的模块,我将扩展方法放入其中,而 DbExtensions 是 .Net 框架的一部分。)

关于.net - 将反射 .GetValue() 对象强转换为通用 DbSet,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10095526/

相关文章:

c# - 尝试从 WebApi 下载文件时任务被取消

wpf - 处置 ReportViewer 对象

c# - EF 核心 : How to add the relationship to shadow property?

c# - 对 Linq 进行分组并将列转换为行

c# - 如何固定变量的精度

html - 使用 CSS 和 HTML 设计 VB.net 表单的样式?

c# - 使用 RegularExpressionValidator 上传文件不适用于 Firefox only IE

c# - 同时将 Entity Framework 与 SQL Server 和 SQLite 数据库一起使用

c# - 类库、 Entity Framework 代码优先和 Microsoft.SqlServer.Types

c# - 如何让垃圾收集器在集合超出范围之前处理该集合?