1

假设我有一个定义了几个实体接口的类库:

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

这个库还定义了一个IRepository接口:

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

最后,该库有一个名为RepositorySourceBase(见下文)的抽象类,主项目需要实现它。此类的目标是允许基类Repository在运行时获取新对象。因为需要某些存储库(在此示例中为ISomeEntityand的存储库ISomeOtherEntity),所以我正在尝试编写该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>();
    }
}

同时,在我的主项目(引用库项目)中,我实现了ISomeEntityand ISomeOtherEntity

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();
            }
        }
    }
}
4

4 回答 4

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是两个方法的有效类型参数,产生两个具有相同签名的方法。

要走的路可能是使用提供的类型参数将调用分派到所需实现的单个泛型方法。反过来,这可能通过在所有具体类型上实现接口最容易解决。

于 2010-05-14T23:37:29.260 回答
1

约束不是签名的一部分。这一事实有许多后果,其中许多显然使人们感到无休止。对于其中的一些后果,以及大约一百万条评论告诉我我错了错了,请参阅这篇文章及其随附的评论。

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

我会通过使用两个具有两个不同名称的方法来解决您的问题。

于 2010-05-15T05:13:10.340 回答
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();
于 2010-05-14T23:52:48.073 回答
0

公共类 RepositorySource {

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

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

}

于 2010-05-15T00:07:10.303 回答