簡體   English   中英

將通用類型傳遞給通用接口

[英]Passing generic type to a generic interface

我正在嘗試實現一個完全通用的CRUD API,由此可以通過上下文傳遞任何類類型並對其進行一般性保存,更新等。

我有一個存儲庫,可以保存任何這樣的模型類型:

public class Repository<T> : IRepository<T> where T : class 
    {
        private Context _db = new Context();

        public T Add(T newItem) 
        {
            var result = _db.Set<T>().Add((T)newItem);
            _db.SaveChanges();

            return result;
        }
    }

這從實現所有“ add”方法的通用接口繼承:

public interface IRepository<T> where T : class
{
    T Add(T newItem);
}

我正在努力理解為什么不能將泛型類型傳遞到存儲庫接口的新實例中? 理想情況下,我想要這樣的東西:

var data = new Data(){
    Id = 1
};

IRepository<data.GetType()> repo = new Repository<data.GetType()>();

從而允許我將任何類型傳遞給方法,並在此方法的后面生成正確的接口。

它允許我傳遞一個具體的類型,但這種方式使將其通用化的目的失敗了。

圍繞此的任何想法或為什么不可能的解釋將不勝感激-謝謝。

嘗試在IRepository本身上使用泛型參數實現泛型存儲庫沒有任何意義,因為術語泛型 (在這種情況下)不是指CLR泛型,而是指存儲庫的性質,即可以與其他庫一起使用與每種類型的存儲庫方法(例如,如ProductsRepository )相比,使用相同存儲庫實例的實體類型也有所不同。

將通用參數放在方法上可以輕松解決問題:

public interface IRepository
{
     T GetById<T>(object id);
     IEnumerable<T> Get<T>(Expression<Func<T, bool>> criteria);
     T Add<T>(T data);
}

使用EntityFramework的可能實現是:

public class EntityFrameworkRepository : IRepository
{
    public T GetById<T>(object id)
    {
        return this.Set<T>().Find(id);
    }

    public IEnumerable<T> Get<T>(Expression<Func<T, bool>> criteria)
    {
        return this.Set<T>().Where(criteria);
    }

    public T Add<T>(T data)
    {
        this.Set<T>().Add(data);
        return data;
    }
}

您遇到了泛型約束 (我本來要使用“局限性”一詞,但這是錯誤的,它不是局限性,相反)。

泛型在編譯時為您提供類型安全性,它允許使用更簡潔的代碼,但您必須在編譯時知道所使用的類型。 如果您似乎直到運行時才知道類型,那么泛型幾乎肯定是錯誤的解決方案。

庫開發人員知道這一點,他們知道您經常不能或不想指定類型,因此他們經常提供非泛型的等效項。 非泛型等效項將Type作為傳統參數而不是泛型參數。

例如,我認為您在EntityFramework中使用DbSet<T> ,但是EntityFramework還提供了一個非通用的DbSet

因此,您的代碼中的這一行:

var result = _db.Set<T>().Add((T)newItem);

可以寫成

var result = _db.Set(newItem.GetType()).Add(newItem);

擴展這一點,您可以定義一個非通用的IRepository

public interface IRepository
{
    object Add(object newItem);
}

並實現為

public class Repository : IRepository
{
    private Context _db = new Context();
    private Type entityType;
    public Repository (Type entityType)
    {
        this.entityType= entityType;
    }

    public object Add(object newItem) 
    {
        var result = _db.Set(entityType).Add(newItem);
        _db.SaveChanges();

        return result;
    }
}

它將起作用,但是您已經失去了所有類型的安全性,從而使Add方法的響應幾乎失效。

總而言之,一旦您遵循了這個兔子漏洞,我懷疑您會回到通用解決方案-比非通用解決方案快幾年(這就是為什么要添加通用!)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM