首页 新闻 会员 周边 捐助

怎么把反射得到的Type ClassType 传入到泛型的Func<TEntity>()?

0
悬赏园豆:60 [待解决问题]

一、问题:

通过反射,可以查找到某个命名空间下的全部类(Class),但是这时是一个数组Type[],数据的内容是Type ClassType。我需要在循环迭达当中,把这个数组里的类型,当作类型参数,传入另一个泛型的方法Func<TEntity>()当中。

在反射当中,得到的类型是Type ClassType;在泛型当中,类型是TEntity。

在构建泛型方法的时候,我们会只定义类型约束TEntity,具体的TEntity交给调用的时候决定。

但是现在的条件是,调用的时候,也不知道具体是哪一个类型。

从ClassType到TEntity中间缺了一环,缺少的这一环是什么?

 

二、背景:

我做的项目当中,EF(Entity Framework)使用的是DB First,客户的需求是不断变动的,数据库里面的表、视图需要经常维护,增减字段是家常便饭。所以平常的流程是,先在文档(word doc)当中写好数据库字典,然后去数据库管理器修改表、视图,然后到模型所在的类库修改类,最后运行整个WEB项目,验证模型的映射是否正常。

数据库-EF-DAL,这个架构是以前公司同事设计的,后来我做别的项目,也是直接套用了这个模式。几个项目之后,我经常想,应该可以写出一个单元测试,以后每添加修改新的表/模型,直接在测试里面验证模型映射的对错。于是几天前就动手了,然后就被这个问题卡住了。

 

三、详细说明

3.1 相关介绍

项目最终的输出是WEB,asp.net MVC。中间还有缓存、XX.BLL什么的。在最底层,XX.DAL封装了EF和一些基础的方法。XX.Model是所有的模型所在的类库。这里XX指代项目的2个字母缩写,或者客户的2个字母缩写,有时候也用我的xpnew前两个字母。

我另外创建了一个类库,XX.DAL.UnitTest。我的目标是在XX.DAL.UnitTest当中找到XX.Model上所有的实体类,可能包含的的“System.Data.Entity.Validation.DbEntityValidationException”和“System.InvalidOperationException.InvalidOperationException”。前者是模型验证的错误,比如说必填字段为空。后者是模型映射错误,比如说数据库里面某个表字段类型是nvarchar,而在XX.Model当中,相应的类的属性定义为int。

 

3.2 代码

 

代码1,单元测试方法:

 1 [TestMethod]
 2         public void TestMethod_循环获取实体()
 3         {
 4 
 5             string AssemblyName = "SA.Model";
 6             Assembly asm2 = Assembly.Load(AssemblyName);
 7             var All = asm2.GetTypes();
 8             foreach (Type T in All)
 9             {
10                 string ClassName = AssemblyName + "." + T.Name;
11                 if (T.FullName == ClassName && T.IsClass)
12                 {
13                     Loger.Debug("准备测试" + T.Name);
14                     dynamic InstanceModel = asm2.CreateInstance(T.FullName);
15                     TryEitity<dynamic>();
16                 }
17                 else
18                 {
19                     Loger.Info(T.FullName + "不是定义的模型内容,跳过");
20                 }
21             }
22 
23         }

代码2,单元测试代码,在泛型的方法中输出错误信息

 1   private void TryEitity<T>() where T : class
 2         {
 3             try
 4             {
 5                 var d = new DAO();
 6                 d.TestEntity<T>();
 7 
 8             }
 9             catch (DbEntityValidationException DbEx)
10             {
11                 foreach (var Err in DbEx.EntityValidationErrors)
12                 {
13                     object CurrentEntity = Err.Entry.Entity;
14                     string TypeName = CurrentEntity.ToString();
15                     StringBuilder sb = new StringBuilder();
16 
17                     sb.Append(TypeName);
18                     sb.Append("发现实体验证错误:");
19                     foreach (var ProErr in Err.ValidationErrors)
20                     {
21                         sb.Append(ProErr.PropertyName);
22                         sb.Append(" 属性错误:");
23                         sb.Append(ProErr.ErrorMessage);
24                     }
25                     SA.Tools.Loger.Error("实体验证错误:" + sb.ToString());
26                 }
27             }
28             catch (Exception ex)
29             {
30                 //if (ex is System.Data.Entity.Validation.DbEntityValidationException)
31                 //{
32                 //    var DbEx = ex as DbEntityValidationException;
33                 //}
34 
35                 SA.Tools.Loger.Error("发现异常:" + ex.Message);
36 
37             }
38         }

代码3,DAL层,专门提供了一个获取实体的方法,面向单元测试:

 1  /// <summary>
 2         /// 测试实体,这是专门为了单元测试而准备的方法
 3         /// </summary>
 4         /// <typeparam name="T"></typeparam>
 5         public List<T> TestEntity<T>() where T : class
 6         {
 7             var AllList = DataContext.Set<T>();
 8             if (null == AllList)
 9             {
10                 return null;
11             }
12             else
13             {
14                 return AllList.ToList();
15             }
16         }

3.3 已知的不行的方案(也有可能是我没搞明白)

3.3.1 没搜索到确切的办法

在网上找了一下相关的资料,基本上没有专门解决这个问题的。比如说,有人在zhihu上提出了一个问题,也被人解答了,但是那个问题实际上只是动态调用实体的方法、属性,属于反射概念范围的。

我现在面临的问题是要跨跃 反射和泛型两个概念

3.3.2  dynamic 关键字

使用 dynamic关键字的办法已经试过了,上面的代码也是这样。但是 dynamic代入到泛型之后是object,而不是我期待的 class UserInfoT,然后在DAL里面执行的时候,无法映射,抛出异常:"实体类型 Object 不是当前上下文的模型的一部分。"

 

 

最后,我有70豆,但是这里好像只能给60个。但是,不管是提供答案的,还是进来看过,都非常感谢!

柳城之城的主页 柳城之城 | 初学一级 | 园豆:39
提问于:2015-10-26 15:35
< >
分享
所有回答(2)
0

仍然是反射调用的问题,想到两个方案:

1.直接反射调用泛型方法

http://stackoverflow.com/questions/232535/how-to-use-reflection-to-call-generic-method

2.声明一个泛型类

public class MapValidator<T>

{

  public void Validate()

  {

    TryEitity<T>();

  }

}

然后通过反射构造对应类型的Validator,调用Validate()方法。

两个方案原理都一样。

LibraJM | 园豆:203 (菜鸟二级) | 2015-10-26 15:53

第一个链接是英文的,我看不了。

第2个,你写的,我看不出跟我提出的问题,有什么关联。

我重复一下(稍后会补充到问题里):通过反射,得到的是XX.Model.UserT ,XX.Model.UserV, XX.Model.NewsT,XX.Model.CheckInOutT。。。。。。这样的类,但是反射得到的是Type ClassType,

接下要有一步转换、变换,然后,代入到一个泛型的方法Func<TEntity>()当中。

现在的问题不是怎么把类型参数代入到方法当中,而是Type ClassType怎么变成TEntity。你说的泛型类里面使用的仍然是TEntity。Type ClassType怎么变成TEntity,仍然还是个问题。

支持(0) 反对(0) 柳城之城 | 园豆:39 (初学一级) | 2015-10-26 18:07
1
[TestMethod]
public void InvokeGenericMethod() {
    var method = this.GetType().GetMethod("DoWork");
    var gm = method.MakeGenericMethod(this.GetType());
    gm.Invoke(this, null);
}

public void DoWork<T>() where T : class {
    Console.WriteLine(typeof(T).FullName);
}

上面的代码是用反射调用泛型方法,可以参考一下有没有帮助。

I,Robot | 园豆:9783 (大侠五级) | 2015-10-26 21:20
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册