2010-05-14 81 views
1

比方說,我有一個類庫,定義了兩個實體的接口:麻煩抽象的通用方法

public interface ISomeEntity { /* ... */ } 
public interface ISomeOtherEntity { /* ... */ } 

該庫還定義了一個IRepository接口:

public interface IRepository<TEntity> { /* ... */ } 

最後,圖書館一個叫RepositorySourceBase的抽象類(見下文),主要項目需要實現。這個類的目標是允許基類在運行時獲取新的對象。因爲需要某些存儲庫(在本例中爲ISomeEntityISomeOtherEntity的存儲庫),所以我試圖編寫GetNew<TEntity>()方法的泛型重載。

下實現不編譯(第二GetNew()方法被標記爲「已定義」,即使在where子句是不同的),但它得到什麼,我試圖完成:

public abstract class RepositorySourceBase // This doesn't work! 
{ 
    public abstract Repository<TEntity> GetNew<TEntity>() 
     where TEntity : SomeEntity; 
    public abstract Repository<TEntity> GetNew<TEntity>() 
     where TEntity : SomeOtherEntity; 
} 

這個類的預期用途會是這樣的:

public class RepositorySourceTester 
{ 
    public RepositorySourceTester(RepositorySourceBase repositorySource) 
    { 
     var someRepository = repositorySource.GetNew<ISomeEntity>(); 
     var someOtherRepository = repositorySource.GetNew<ISomeOtherEntity>(); 
    } 
} 

同時,比我的主項目(引用庫項目),我公頃已經的ISomeEntityISomeOtherEntity實現:

public class SomeEntity : ISomeEntity { /* ... */ } 
public class SomeOtherEntity : ISomeOtherEntity { /* ... */ } 

主要項目也已經爲IRepository<TEntity>實現:

public class Repository<TEntity> : IRepository<TEntity> 
{ 
    public Repository(string message) { } 
} 

而且最重要的是,它具有抽象RepositorySourceBase的實現:

public class RepositorySource : RepositorySourceBase 
{ 
    public override IRepository<ISomeEntity> GetNew() 
    { 
     return new (IRepository<ISomeEntity>)Repository<SomeEntity>(
      "stuff only I know"); 
    } 

    public override IRepository<ISomeOtherEntity> GetNew() 
    { 
     return new (IRepository<ISomeEntity>)Repository<SomeOtherEntity>(
      "other stuff only I know"); 
    } 
} 

RepositorySourceBase一樣,第二個GetNew()方法獲取標記爲「已定義」。


所以,C#基本上認爲我重複着同樣的方法,因爲沒有辦法來區分他們的參數單獨的方法,但是如果你看一下我的使用例子,好像我應該能夠以區分哪個GetNew()我想要的泛型類型參數,例如,<ISomeEntity><ISomeOtherEntity>)。

我需要做些什麼才能使其發揮作用?


更新

我最終解決這個使用專門命名方法和Func<T, TResult>參數。

所以,RepositorySourceBase現在看起來是這樣的:

public abstract class RepositorySourceBase 
{ 
    public abstract Repository<ISomeEntity> GetNewSomeEntity(); 
    public abstract Repository<ISomeOtherEntity> GetNewSomeOtherEntity(); 
} 

而且RepositorySource看起來是這樣的:

public class RepositorySource : RepositorySourceBase 
{ 
    public override IRepository<ISomeEntity> GetNewSomeEntity() 
    { 
     return new (IRepository<ISomeEntity>)Repository<SomeEntity>(
      "stuff only I know"); 
    } 

    public override IRepository<ISomeOtherEntity> GetNewSomeOtherEntity() 
    { 
     return new (IRepository<ISomeEntity>)Repository<SomeOtherEntity>(
      "other stuff only I know"); 
    } 
} 

現在,開始這件事過了,我需要一個通用的RepositoryUtilizer類可能只需知道存儲庫的類型(可將其指定爲泛型類型參數)即可從源獲取存儲庫。原來,這是不可能的(或者至少不容易)。但是,可能的是使用Func<T, TResult>委託作爲參數,以允許RepositoryUtilizer類獲取存儲庫,而無需「知道」方法名稱。

下面是一個例子:

public class RepositoryUtilizer 
{ 
    public DoSomethingWithRepository<TEntity>(
     Func<TRepositorySource, IRepository<TEntity>> repositoryGetter) 
     { 
      using (var repository = repositoryGetter(RepositorySource)) 
      { 
       return repository.DoSomething(); 
      } 
     } 
    } 
} 

回答

1

約束不是簽名的一部分。這個事實有許多後果,其中許多顯然使人們不知所措。對於其中的一些後果,以及大約一百萬條評論告訴我,我是錯誤的錯誤,請參閱本文及其隨附的評論。

http://blogs.msdn.com/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx

我會被有兩種方法有兩個不同的名稱解決您的問題。

+0

+1。感謝您的回答和鏈接,Eric。我設法實現了我使用專門命名的方法(如你所建議的)和一個'Func'參數尋找的結果,該參數允許我使用lambda表達式從源獲取存儲庫。不像只能指定我想要的類型那麼漂亮,但它基本上完成了我一直在尋找的「通用性」的程度:) – devuxer 2010-05-15 18:19:19

2

,你打算你不能得到這個工作。不能使用類型約束來決定兩種方法。

public abstract Repository<TEntity> GetNew<TEntity>() 
    where TEntity : SomeEntity; 

public abstract Repository<TEntity> GetNew<TEntity>() 
    where TEntity : SomeOtherEntity; 

假設

public class SomeEntity { } 

public class SomeOtherEntity : SomeEntity { } 

SomeOtherEntity是對於兩種方法得到的兩種方法具有相同簽名的有效類型參數。

要走的路可能是一個單一的泛型方法,它使用提供的類型參數來調用所需的實現。這反過來很可能通過在所有具體類型上實現一個接口來解決。

+0

+1即使它不是我想要聽到的答案:)有沒有什麼辦法可以使簽名不同而不需要實例化對象? (我不能實例化任何東西,因爲庫類只知道接口,而不是實現。) – devuxer 2010-05-14 23:47:00

0

我能想到的唯一的解決辦法是定義一個IRepositorySource<T>接口,每個RepositorySource類可以顯式實現:

public interface IRepositorySource<T> 
{ 
    IRepository<T> GetNew(); 
} 

public class RepositorySource : IRepositorySource<ISomeEntity>, IRepositorySource<ISomeOtherEntity> 
{ 
    IRepository<ISomeEntity> IRepositorySource<ISomeEntity>.GetNew() 
    { 
     ... 
    } 

    IRepository<ISomeOtherEntity> IRepositorySource<ISomeOtherEntity>.GetNew() 
    { 
     ... 
    } 
} 

要訪問這些方法,你需要施放RepositorySource實例成所需要的接口類型例如

IRepository<IEntity> r = ((IRepositorySource<IEntity>)repositorySource).GetNew(); 
0

公共類RepositorySource {

static IRepository<T> IRepositorySource.GetNew<T>() 

{ 
    if (typeof(T) == typeof(ISomeEntity)) 
     return (IRepository<T>)new SomeEntityRepository(); 
    ... 
} 

}