【问题标题】:C# Dynamic generic instanceC# 动态泛型实例
【发布时间】:2017-02-09 14:54:23
【问题描述】:

这是我在这里的第一个问题,我对 C# 术语不是很熟悉,所以如果我混淆了一些术语或定义,我会提前道歉。

我已经设置了一个通用的 EF 数据访问层;

public class BaseService<TObject> where TObject : class
{
    private DbContext Context;
    private static readonly Lazy<BaseService<TObject>> lazy = new Lazy<BaseService<TObject>>(() => new BaseService<TObject>());
    public static BaseService<TObject> Instance => lazy.Value;

    public BaseService()
    {
        Context = new evEntities();
    }

    public BaseService(DbContext context)
    {
        Context = context;
    }

    public ICollection<TObject> GetAll()
    {
        return Context.Set<TObject>().ToList();
    }

    public async Task<ICollection<TObject>> GetAllAsync()
    {
        return await Context.Set<TObject>().ToListAsync();
    }

    public TObject Get(int id)
    {
        return Context.Set<TObject>().Find(id);
    }
}

连同这个;

public static class DA
{
    public static DataAccess.Categories Categories => new DataAccess.Categories();
    public static DataAccess.Tags Tags => new DataAccess.Tags();
    public static DataAccess.Users Users => new DataAccess.Users();
}

public static class DA<T> where T : class
{
    public static BaseService<T> Base => new BaseService<T>();
}

所以在我的业务层中我可以做到这一点;

public class Categories
{
    public Categories() { }

    public ICollection<Database.Categories> GetAll()
    {
        return DA.Categories.GetAll().ToList();
    }

    public async Task<ICollection<Database.Categories>> GetAllAsync()
    {
        return await DA.Categories.GetAllAsync();
    }

    public Database.Categories Get(int id)
    {
        return DA.Categories.Get(id);
    }
}

为了清楚起见。我的 EF 创建了像“Database.Categories”和“Database.Users”这样的类/实体,我将它们作为“TObject”传递给我的 BaseService 以获得从我的数据库中为所有实体提取数据的标准方法.

现在我的问题。以类似的方式,我想创建一个通用的业务层。喜欢;

public class BusinessLogicBase<TModel>
{
    public ICollection<TDBModel> GetAll()
    {
        return null;
    }

    public async Task<ICollection<TDBModel>> GetAllAsync()
    {
        return await DA.Categories.GetAllAsync();
    }

    public TDBModel Get(int id)
    {
        return DA.Categories.Get(id);
    }
}

我希望能够使用诸如 Database.Categories 之类的 TObject 调用 DA,但这必须是动态的,基于传递给 BusinessLogicBase 的类型。所以我想做这样的事情(这是行不通的);

private ???? DetermineDatabaseModel()
{
    switch(typeof(TModell))
    {
        case Models.Categories:
            return Database.Categories;
        case Models.Users:
            return Database.Users;
    }
}

所以我可以这样做;

public ICollection<TDBModel> GetAll()
{
    var databaseModel = DetermineDatabaseModel()
    return DA<databaseModel>().GetAll();
}

希望你能理解我的问题并能帮助我。

谢谢!

抱歉发了这么长的帖子,对于你们这些 9gaggers,这是一个土豆……不开玩笑,这是认真的。

【问题讨论】:

  • 你可以离开大部分 EF 部分,因为你的牛肉是“我如何告诉计算机处理两种相同的类型,它们彼此之间没有任何关系,只是它们是相同的 给我”。假设 TModel 和 TObject 具有相同的属性,您可以使用 AutoMapper 来映射属性。
  • 嗨 Janne,这并不完全正确。我知道它们是不一样的,我并不是试图说服计算机将它们视为相同。我想要一个函数来根据传递的泛型返回要用作泛型的数据类型。

标签: c# entity-framework generics data-access-layer business-logic-layer


【解决方案1】:

您是否尝试过类似的方法:

public class BusinessLogicBase<TDBModel> where TDBModel : class {
  public ICollection<TDBModel> GetAll() {
    return DA<TDBModel>.Base.GetAll();
  }
}

更新 1:

如果您先尝试在没有泛型的情况下编写它,然后使用泛型将其转换为更通用的模式,也许会对您有所帮助。有些失误在没有泛型的情况下更容易解决。

方法public ICollection&lt;TDBModel&gt; GetAll() 无法返回ICollection&lt;TDBModel&gt;,因为类型参数TDBModel 未在类签名或方法签名中定义。如果你这样定义它,我会更有意义:

public class BusinessLogicBase<TModel>
{
    public ICollection<TModel> GetAll()
    {
        return null;
    }
}

更新 2:

尝试this simple console app 演示dynamic 关键字并观察变量categoriesusers 中存储的内容。

更新 3:

基于小提琴 - 我已将 IBaseService&lt;dynamic&gt; 更改为 dynamic

public class BL<TModel>
{
    // This is what i want to make dynamic.
    // how do i create a return type that i can use in DA<>..
    private Type testDetermineDatabaseModel()
    {
        switch(typeof(TModel).Name){
            case "Categories":
                return typeof(Database.Categories);
            case "Users":
                return typeof(Database.Users);
        }

        return null;
    }

    public ICollection<TModel> testGetAll() 
    {
        var databaseModel = testDetermineDatabaseModel();
        // return DA<databaseModel>().Base.GetAll();
        return new List<TModel>();
    }

    // NEW
    // I have constructed the following.
    private dynamic  baseService;

    public dynamic DetermineDatabaseModel()
    {
        switch (typeof(TModel).Name)
        {
            case "Categories":
                return new BaseService<Database.Categories>();
            case "Users":
                return new BaseService<Database.Users>();
            default:
                return null;
        }
    }

    private IBaseService<TDbModel> GetBase<TDbModel>() where TDbModel : class
    {
        return new BaseService<TDbModel>();
    }

    public ICollection<TModel> GetAll()
    {

        ICollection<TModel> returnValue = new List<TModel>();
        // This works!!!
        foreach (var item in GetBase<Database.Categories>().GetAll())
        {
            returnValue.Add((TModel)(object)item);
        }

        baseService = DetermineDatabaseModel();
        // This doesn't!!! It's the same thing!! :(
        foreach (var item in baseService.GetAll())
        {
            returnValue.Add((TModel)(object)item);
        }

        return returnValue;
    }
}

但请记住,这并不能解决您面临的问题。那是 map 2 泛型类型。

【讨论】:

  • 嗨 Dolphin,是的,我做到了,但我不想在调用 BLL 时传递数据库对象。
  • 嗨,所以基本上你只想知道DetermineDatabaseModel方法应该是什么样子?在那种情况下,我明天会更新答案。
  • 是的:D Thnx!我会热切地等待你的回答:D
  • 我还是不明白为什么不能使用静态泛型 DA。如果您坚持使用方法“DetermineDatabaseModel”,则必须使用反射 - 您不能使用方法返回类型参数,但您可以返回类型本身 typeof(TDBModel) 返回类型将为“System.Type”。
  • 我试过了,但是我得到一个错误:'databaseModel'是一个变量,但被用作一个类型。。我更改了DetermineDatabaseModel 以返回typeof(Database.Categories)。我没有死心塌地使用这种方法,你有什么建议吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
  • 1970-01-01
相关资源
最近更新 更多