代码之家  ›  专栏  ›  技术社区  ›  devuxer

抽象泛型方法有问题

  •  1
  • devuxer  · 技术社区  · 15 年前

    假设我有一个类库,它定义了两个实体接口:

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

    此库还定义了 IRepository 接口:

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

    最后,这个库有一个抽象类叫做 RepositorySourceBase Repository 运行时的对象。因为需要某些存储库(在本例中为 ISomeEntity ISomeOtherEntity ),我正在尝试编写 GetNew<TEntity>() 方法。

    下面的实现没有编译(第二个) GetNew() 方法被标记为“already defined”,即使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>();
        }
    }
    

    同时,在我的主项目(引用库项目)中,我有 等距实体 ISomeOtherEntity公司

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

    IRepository<TEntity> :

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

    最重要的是,它有一个抽象的实现 存储资源库

    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");
        }
    }
    

    就跟你一样 存储资源库 GetNew()


    参数 GetNew() 我想从泛型类型参数,例如, <ISomeEntity> <ISomeOtherEntity> ).

    我要怎么做才能让它工作?


    更新

    Func<T, TResult> 参数。

    所以, 存储资源库 现在看起来像这样:

    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 类,只需知道存储库的类型(可以指定为泛型类型参数),即可从源中获取存储库。事实证明,这是不可能的(或者至少不容易做到)。但是,什么 函数(&L);T、 T结果> 委托作为参数,以允许 类来获取存储库,而不需要“知道”方法名。

    举个例子:

    public class RepositoryUtilizer
    {
        public DoSomethingWithRepository<TEntity>(
            Func<TRepositorySource, IRepository<TEntity>> repositoryGetter)
            {
                using (var repository = repositoryGetter(RepositorySource))
                {
                    return repository.DoSomething();
                }
            }
        }
    }
    
    4 回复  |  直到 15 年前
        1
  •  1
  •   Eric Lippert    15 年前
        2
  •  2
  •   Daniel Brückner    15 年前

    你不能如愿完成这项工作。类型约束不能用于决定两个方法之间的关系。

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

        3
  •  0
  •   Lee    15 年前

    我能想到的唯一解决办法就是定义一个 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();
    
        4
  •  0
  •   Vlad    15 年前

    {

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