繁体   English   中英

如何使用通用方法实现接口?

[英]How can you implement an interface with a generic method?

考虑以下类和接口:

interface INameable
{
    string Name { get; }
}

interface IRepository<T>
{
    void Add(T obj);
    IEnumerable<T> Values { get; }
}

class Person : INameable
{
    public string Name { get; set; }
    public int Age { get; set; }
}

class Car : INameable
{
    public string Name { get; set; }
    public string Model { get; set; }
}

我现在想创建一个同时实现IRepository<Car>IRepository<Person>的Repository类。 这是一个示例实现:

class Repository : IRepository<Car>, IRepository<Person>
{
    Dictionary<string, object> values = new Dictionary<string, object>();

    void AddValue(INameable o)
    {
        values.Add(o.Name, o);
    }

    IEnumerable<T> ValuesOfType<T>() 
    {
        return values.Values.OfType<T>();
    }

    void IRepository<Car>.Add(Car obj)
    {
        AddValue(obj);
    }

    void IRepository<Person>.Add(Person obj)
    {
        AddValue(obj);
    }

    IEnumerable<Car> IRepository<Car>.Values
    {
        get { return ValuesOfType<Car>(); }
    }


    IEnumerable<Person> IRepository<Person>.Values
    {
        get { return ValuesOfType<Person>(); }
    }
}

这完全符合预期。 但是,这是非常重复的。 IRepository<Person>IRepository<Car>的实现代码几乎完全相同。

我想做的是为所有T实现IRepository ,其中TINameable 我尝试了这个:

class Repository2 : IRepository<Car>, IRepository<Person>
{
    // same as before
    Dictionary<string, object> values = new Dictionary<string, object>();

    void AddValue(INameable o)
    {
        values.Add(o.Name, o);
    }

    IEnumerable<T> ValuesOfType<T>() 
    {
        return values.Values.OfType<T>();
    }


    // using generics to implement both the interfaces
    void Add<T>(T obj) where T : INameable
    {
        AddValue(obj);
    }

    void Values<T>() where T : INameable
    {
        return ValuesOfType<T>();
    }

}

但是我得到类似的错误:

ConsoleApp.Repository2' does not implement interface member 'ConsoleApp.IRepository<ConsoleApp.Car>.Add(ConsoleApp.Car)'

我不确定为什么Add<T>Vales<T>方法不匹配-可以将T都设置为PersonCar ,然后它们将完全匹配所需的方法类型。

最后,我尝试了:

class Repository3 : IRepository<T> where T is INameable {... }

但是,出现错误“非泛型声明中不允许约束”。

解决此问题的最佳方法是什么?

请注意,我这样做是为了简单地访问DbContext类(该类具有对应用程序中每个表的引用)的方法,因此,我没有传递完整的数据库给每个控制器,而是仅传递了需要的数据。 我这样做是为了更好地将数据库与应用程序的其余部分分开,并提高可测试性。 如果有更好的方法可以帮助您。

以我的经验,要添加到某个存储库中的所有实体都遵循某个接口(例如IBaseObjectIBaseObject

interface IRepository
{
    void Add(IBaseObject obj);
    IEnumerable<IBaseObject> Values { get; }
}

通常,这最终是一个很好的解决方案,因为在IBaseObject可以有一个标识符,以便您知道何时添加或更新现有记录。

更新:

另一种方法是使用以下模式,同样仍然依赖IBaseObject

interface IRepository
{
   void Add(T obj) where T : IBaseObject;
   IEnumerable<T> GetValues() where T : IBaseObject;
}

您可以在实现中创建一个抽象类,然后只为特定类型继承它。

public interface INameable
{
    string Name { get; }
}

public interface IRepository<T>
{
    void Add( T obj );
    IEnumerable<T> Values { get; }
}

public class Person : INameable
{
    public string Name { get; set; }
    public int Age { get; set; }
}

public class Car : INameable
{
    public string Name { get; set; }
    public string Model { get; set; }
}

public abstract class AbstractRepository<T> : IRepository<T>
    where T : INameable
{
    // same as before
    Dictionary<string, object> values = new Dictionary<string, object>();

    void AddValue( INameable o )
    {
        values.Add( o.Name, o );
    }

    IEnumerable<T> ValuesOfType<T>()
    {
        return values.Values.OfType<T>();
    }


    // using generics to implement both the interfaces
    public void Add( T obj ) 
    {
        AddValue( obj );
    }

    public IEnumerable<T> Values 
    {
        get
        {
            return ValuesOfType<T>();
        }
    }
}


public class CarRepository : AbstractRepository<Car> { }

public class PersonRepository : AbstractRepository<Person> { }

我认为,您应该创建创建存储库的类。 像这样:

    class Repository<T> : IRepository<T>
    where T : INameable
{
    Dictionary<string, T> values = new Dictionary<string, T>();

    void AddValue(T o)
    {
        values.Add(o.Name, o);
    }

    public void Add(T obj)
    {
        AddValue(obj);
    }

    public IEnumerable<T> Values
    {
        get { return values.Values; }
    }
}

class UnitOfWork
{
    private readonly Dictionary<Type, object> _repositories = new Dictionary<Type, object>();

    public IRepository<T> GetRepository<T>()
        where T : INameable
    {
        object repository;
        if (!_repositories.TryGetValue(typeof (T), out repository))
        {
            repository = new Repository<T>();
            _repositories[typeof (T)] = repository;
        }
        return (IRepository<T>)repository;
    }
}

并像这样使用它:

        var unitOfWork = new UnitOfWork();

        unitOfWork.GetRepository<Car>().Add(new Car {Name = "Audi"});
        unitOfWork.GetRepository<Car>().Add(new Car { Name = "BMW" });

        foreach (var car in unitOfWork.GetRepository<Car>().Values)
            Console.WriteLine(car.Name);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM