c# - 基于泛型参数实例化具体类c#

标签 c# entity-framework generics

好吧,我试着把我的想法围绕在这个问题上,但没有运气;找不到更好的解决方案,所以我很乐意使用一些帮助/想法。

基本上,我有一个通用方法,它接收一个 businessobject 作为通用参数,它应该实例化一个 EntityFramework 实体并返回它。业务对象名称和 Entity Framework 名称之间存在命名约定(即,如果 BO 命名为“UsersBo”,则 EF 实体命名为“Users”)并且该约定在任何地方都强制执行。

我的代码是这样的:

public dynamic CreateEntity<T>()
{
    switch (typeof(T).Name)
    {
        case "UsersBo":
           return new Users();
        case "RolesBo":
           return new Roles();
        case "AppObjectsBo":
           return new AppObjects();
        default:
           break;
    }
    return null;
}

我有两个问题:

  1. 考虑到 BO 和 EF 实体位于不同的 DLL 中(BLL.dll 与 DAL.dll),如果没有那个丑陋的 switch 命令,我该如何实例化它呢?尝试使用 Activator.CreateInstance,它给了我关于“完全限定名称”的错误

  2. 有什么方法可以使用动态对象吗?现在我正在使用动态,因为我不知道将实例化哪个具体类。

谢谢

================================ 稍后编辑:

这是实际的代码:

public T GetById(Guid id)
        {
            T entityBo = new T();
            var entity = new EntityFactory().CreateEntity<T>();
            var repository = new EntityFactory().CreateRepository<T>();
            try
            {
                entity = repository.GetById(id);
                if (entity != null)
                {
                    Mapper.Map(entity, entityBo);
                }
            }
            catch (Exception ex)
            {
                entityBo = default(T);
                throw ex.GetBaseException();
            }
            return entityBo;
        }

===================== 我有一个与业务对象一起使用的通用服务类。当然,这些必须映射到相应的 EF 对象。

如果我使用 UsersBo 作为 T 调用上述方法,代码将变为:

public UsersBo GetById(Guid id)
        {
            UsersBo entityBo = new UsersBo(); // no problem here
            var entity = new EntityFactory().CreateEntity<T>(); // That's the problem line: T is UsersBo, but I need a new Users (EF entity) in order to do the mapping later
            var repository = new EntityFactory().CreateRepository<T>();
            try
            {
                entity = repository.GetById(id); // this one returns the EF entity
                if (entity != null)
                {
                    Mapper.Map(entity, entityBo);
                }
            }
            catch (Exception ex)
            {
                entityBo = default(T);
                throw ex.GetBaseException();
            }
            return entityBo;
        }

希望现在更有意义。我对任何建议都持开放态度,也许我完全不了解并且有更好的方法。

谢谢你们。

=============

睡过头了。一流的答案,已经更改了代码并且像魅力一样工作。谢谢你们,你们帮了大忙。

最佳答案

你可以做这样的事情,但我仍然不喜欢整体设计,因为你放弃了关键字 dynamic 的类型安全。最好使用传入的类型约束来取回您要在调用代码中使用的确切类型。

// personally i would change dynamic to object
// calling code could always cast to dynamic if it needed to
public dynamic CreateEntity<T>()
{
    var bllName = typeof(T).Name;
    var efName = bllName.Substring(0, bllName.Length - 2); // removes "Bo"

    var className = string.Concat("Namespace.", efName, ", EfAssembly.dll");
    var efType = Type.GetType(className);
    return efType != null ? Activator.CreateInstance(efType) : null;
}

这(请参阅下面的代码)是我的偏好,此处 T 将是您要在调用代码中使用的实际 EF 实体,并且与您的 BLL 类型完全无关。或者,您可以丰富 BLL 类型以返回正确的 EF 类型,但不利的是 SoC,因为您会打破松耦合规则。

public T CreateEntity<T>() where T : class, new()
{
    return new T();
}

根据您最近的修改,我改进了您的代码以及您可以如何处理此问题。

public T GetById<T>(Guid id) where T : new()
{
    T entityBo = new T();

    // this should not be needed, you do not use the results anywhere unless your EF type provides for some defaults at the BLL layer but it would be better to include those defaults in the BLL types constructor instead
    // var entity = new EntityFactory().CreateEntity<T>(); // That's the problem line: T is UsersBo, but I need a new Users (EF entity) in order to do the mapping later

    // this is the line where you need to implement the translation to get the correct repository type
    var repository = new EntityFactory().CreateRepository<T>();
    try
    {
        // get your object from your repository or if it returns null then you will end up just returning the default bll instance which is OK
        var entity = repository.GetById(id);
        if (entity != null)
        {
            // map what was returned
            Mapper.Map(entity, entityBo);
        }
    }
    catch (Exception ex)
    {
        // no need for this, it adds nothing
        // entityBo = default(T);

        // do not do this
        // throw ex.GetBaseException();

        // this is better, it preserves the stack trace and all exception details
        throw;
    }
    return entityBo;
}

关于c# - 基于泛型参数实例化具体类c#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38874933/

相关文章:

c# - 泛型类型转换

c# - XML 架构 (XSD) 到实体对象模型

c# - 代码优先数据库迁移

java - 可以用泛型类型实例化 List<T> 吗?

c# - 如何编写 EF Core 查询以过滤多个表?

c# - 将值从 Angular Controller 传递到 C# API

java - 广泛使用 Java 泛型有什么缺点吗?

ios - 在 Swift 扩展方法(数组)中使用未声明的类型 'Element'

c# - 异常:指定类别中不存在实例 'Name of instance'

c# - linq中的switch case