C# 抽象泛型方法的问题
假设我有一个类库,它定义了两个实体接口:C# 抽象泛型方法的问题,c#,generics,fluent,C#,Generics,Fluent,假设我有一个类库,它定义了两个实体接口: public interface ISomeEntity { /* ... */ } public interface ISomeOtherEntity { /* ... */ } 此库还定义了一个IRepository接口: public interface IRepository<TEntity> { /* ... */ } 此类的预期用途如下: public class RepositorySourceTester { pu
public interface ISomeEntity { /* ... */ }
public interface ISomeOtherEntity { /* ... */ }
此库还定义了一个IRepository
接口:
public interface IRepository<TEntity> { /* ... */ }
此类的预期用途如下:
public class RepositorySourceTester
{
public RepositorySourceTester(RepositorySourceBase repositorySource)
{
var someRepository = repositorySource.GetNew<ISomeEntity>();
var someOtherRepository = repositorySource.GetNew<ISomeOtherEntity>();
}
}
public abstract class RepositorySourceBase
{
public abstract Repository<ISomeEntity> GetNewSomeEntity();
public abstract Repository<ISomeOtherEntity> GetNewSomeOtherEntity();
}
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");
}
}
主项目还实现了IRepository
:
与RepositorySourceBase
一样,第二个GetNew()
方法被标记为“已定义”
因此,C#基本上认为我在重复相同的方法,因为无法单独将方法与参数区分开来,但是如果你看看我的使用示例,我似乎应该能够从泛型类型参数中区分出我想要的
GetNew()
,例如,
或
)
我需要做些什么才能让它工作
更新 最后,我使用专门命名的方法和
Func
参数解决了这个问题
因此,RepositorySourceBase
现在看起来是这样的:
public class RepositorySourceTester
{
public RepositorySourceTester(RepositorySourceBase repositorySource)
{
var someRepository = repositorySource.GetNew<ISomeEntity>();
var someOtherRepository = repositorySource.GetNew<ISomeOtherEntity>();
}
}
public abstract class RepositorySourceBase
{
public abstract Repository<ISomeEntity> GetNewSomeEntity();
public abstract Repository<ISomeOtherEntity> GetNewSomeOtherEntity();
}
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
委托作为参数,以允许RepositoryUtilizer
类在不需要“知道”方法名称的情况下获取存储库
下面是一个例子:
public class RepositoryUtilizer
{
public DoSomethingWithRepository<TEntity>(
Func<TRepositorySource, IRepository<TEntity>> repositoryGetter)
{
using (var repository = repositoryGetter(RepositorySource))
{
return repository.DoSomething();
}
}
}
}
公共类RepositoryUtilizer
{
公共DoSomethingWithRepository(
Func repositoryGetter)
{
使用(var repository=repositoryGetter(RepositorySource))
{
返回repository.DoSomething();
}
}
}
}
您无法按预期完成此工作。类型约束不能用于决定两种方法之间的关系
public abstract Repository<TEntity> GetNew<TEntity>()
where TEntity : SomeEntity;
public abstract Repository<TEntity> GetNew<TEntity>()
where TEntity : SomeOtherEntity;
而SomeOtherEntity
是两个方法的有效类型参数,生成两个具有相同签名的方法
方法可能是使用提供的类型参数将调用分派到所需实现的单个泛型方法。反过来,在所有具体类型上实现接口可能最容易解决这一问题。我能想到的唯一解决方案是定义每个RepositorySource类可以显式实现的
IRepositorySource
接口:
public interface IRepositorySource<T>
{
IRepository<T> GetNew();
}
public class RepositorySource : IRepositorySource<ISomeEntity>, IRepositorySource<ISomeOtherEntity>
{
IRepository<ISomeEntity> IRepositorySource<ISomeEntity>.GetNew()
{
...
}
IRepository<ISomeOtherEntity> IRepositorySource<ISomeOtherEntity>.GetNew()
{
...
}
}
公共接口IRepositorySource
{
i假定GetNew();
}
公共类存储源:IRepositorySource,IRepositorySource
{
IRepository IRepositorySource.GetNew()
{
...
}
IRepository IRepositorySource.GetNew()
{
...
}
}
要访问这些方法,您需要将RepositorySource实例强制转换为所需的接口类型,例如
IRepository<IEntity> r = ((IRepositorySource<IEntity>)repositorySource).GetNew();
IRepository r=((IRepositorySource)repositorySource).GetNew();
公共类存储源
{
静态IRepository IRepositorySource.GetNew()
{
if(类型(T)=类型(实体))
return(IRepository)newsomentityrepository();
...
}
}约束不是签名的一部分。这一事实产生了许多后果,其中许多显然让人们无穷无尽地感到厌烦。对于其中的一些后果,以及大约一百万条告诉我我错了的评论,请参阅本文及其附带的评论
我可以通过使用两个名称不同的方法来解决您的问题。+1即使这不是我想要听到的答案:)有没有任何方法可以让签名不同,而无需实例化对象?(我不能实例化任何东西,因为库类只知道接口,不知道实现。)+1。谢谢你的回答和链接,埃里克。我通过使用特定命名的方法(如您所建议的)和一个
Func
参数实现了我想要的结果,该参数允许我使用lambda表达式从源代码获取存储库。虽然没有能够指定我想要的类型那么漂亮,但它基本上达到了我想要的“泛型性”程度:)
public interface IRepositorySource<T>
{
IRepository<T> GetNew();
}
public class RepositorySource : IRepositorySource<ISomeEntity>, IRepositorySource<ISomeOtherEntity>
{
IRepository<ISomeEntity> IRepositorySource<ISomeEntity>.GetNew()
{
...
}
IRepository<ISomeOtherEntity> IRepositorySource<ISomeOtherEntity>.GetNew()
{
...
}
}
IRepository<IEntity> r = ((IRepositorySource<IEntity>)repositorySource).GetNew();
static IRepository<T> IRepositorySource.GetNew<T>()
{
if (typeof(T) == typeof(ISomeEntity))
return (IRepository<T>)new SomeEntityRepository();
...
}