2012-10-18 24 views
1

我對C#很陌生,目前正在開發一個使用EntityFramework的應用程序。我想擴展數據庫上下文類的功能,以便我可以調用方法getPool(),以便它發出該類的相應DbSet成員。C#:專門的模板方法 - 錯誤:類型'...'已經定義了一個名爲'...'的成員具有相同的參數類型

我需要將它作爲一個模板來實現,因爲它稍後將從其他模板中調用,這些模板只知道(全局)數據庫上下文對象和類型T(具有給定的超類)數據庫。

這裏是我試了一下(有點簡單化 - 原來的例子太複雜):

public class TestContext : DbContext 
{ 
    public DbSet<TestA> ATests { get; set; } 
    public DbSet<TestB> BTests { get; set; } 

    public IQueryable<T> getPool<T>() where T : TestA { 
     return (IQueryable<T>)ATests; 
    } 
    public IQueryable<T> getPool<T>() where T : TestB { 
     return (IQueryable<T>)BTests; 
    } 
} 

的錯誤消息是

錯誤:類型「...」已經定義了一個名爲成員'...'使用相同的參數類型

它發生在我的模板(public IQueryable<T> getPool<T>() where T : TestB)的第二個專門定義的行。

問題是:如何解決這個問題?

+0

只是評論:C#中使用術語泛型類型/方法,雖然語法可能類似由C++模板,他們有很大的不同。 –

+0

這就是他所有的誤解來自哪裏,看到最後一句使用C++的措辭(在這種情況下,這不完全正確)。 @Stefan K .:我真的推薦深入瞭解模板和泛型之間的概念差異,否則你將沒有運氣...... –

回答

4

不幸的是,在C#中,不能通過使用像這樣的泛型類型約束來重載方法。你必須給他們不同的名字,像這樣

public class TestContext : DbContext 
{ 
    public DbSet<TestA> ATests { get; set; } 
    public DbSet<TestB> BTests { get; set; } 

    public IQueryable<T> getPoolA<T>() where T : TestA { 
     return (IQueryable<T>)ATests; 
    } 
    public IQueryable<T> getPoolB<T>() where T : TestB { 
     return (IQueryable<T>)BTests; 
    } 
} 

另一種解決辦法是做這樣的事情:

public class TestContext : DbContext 
{ 
    public DbSet<TestA> ATests { get; set; } 
    public DbSet<TestB> BTests { get; set; } 

    public IQueryable<T> getPool<T>() { 
     return (typeof(T) == typeof(TestA)) 
        ? (IQueryable<T>)ATests 
        : (IQueryable<T>)BTests; 
    } 
} 

現在,你可以讓這個更清潔,因爲IQueryable<T>T協變,你能避免鑄造:

public class TestContext : DbContext 
{ 
    public DbSet<TestA> ATests { get; set; } 
    public DbSet<TestB> BTests { get; set; } 

    public IQueryable<T> getPool<T>() { 
     return (typeof(T) == typeof(TestA)) ? ATests : BTests; 
    } 
} 

如果你想牛逼Ø避免類型的測試,你可以做這樣的事情:

public class TestContext : DbContext 
{ 
    readonly Dictionary<Type, object> _sets; 

    public DbSet<TestA> ATests { get; set; } 
    public DbSet<TestB> BTests { get; set; } 

    public TestContext() 
    { 
     _sets = new Dictionary<Type, object> 
     { 
      { typeof(TestA), ATests }, 
      { typeof(TestB), BTests } 
     } 
    } 

    public IQueryable<T> getPool<T>() { 
     return (IQueryable<T>)_sets[typeof(T)]; 
    } 
} 
+0

最後的解決方案是,我想避免,因爲這裏有很多類型上下文。這將最終在一個巨大的開關/ case-statement ...我甚至會使用typeof(T).Name,因爲開關(typeof(T))不起作用;-) – SDwarfs

+0

@StefanK。請看我最後的編輯 - 這有幫助嗎? –

+0

我認爲詞典解決方案作爲一個妥協是好的。 – SDwarfs

1

我建議你(的除了閱讀泛型和C#一般)來配置與運行時所需的類型庫,將它們存儲在詞典和使用Type爲重點,即沿以下路線的東西...:

//... 

// configuration, maybe factor out to a dedicated class... 
private readonly IDictionary<System.Type, IQueryable> m_SupportedPools = 
    new Dictionary<System.Type, IQueryable>(); 

// add this queryable, note that type inference works here 
public void AddToPool<T>(IQueryable<T> p_Queryable) 
{ 
    m_SupportedPools.Add(typeof(T), p_Queryable); 
} 

public IQueryable<T> GetPool<T>() 
{ 
    IQueryable t_Set = null; 
    if (m_SupportedQueries.TryGetValue(typeof(T), out t_Set)) { 
     return t_Set as IQueryable<T>; 
    } else { 
     return null; 
    } 
} 
相關問題