C# 如何使用泛型方法实现接口?

C# 如何使用泛型方法实现接口?,c#,generics,C#,Generics,考虑以下类和接口: 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; se

考虑以下类和接口:

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; }
}
但是,我会遇到如下错误:

ConsoleApp.Repository2' does not implement interface member 'ConsoleApp.IRepository<ConsoleApp.Car>.Add(ConsoleApp.Car)'
但是,我得到一个错误“非泛型声明上不允许约束”

解决这个问题的最好办法是什么


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

根据我的经验,要添加到某个存储库中的所有实体都符合某个接口,比如说
IBaseObject
,要容易得多:

interface IRepository
{
    void Add(IBaseObject obj);
    IEnumerable<IBaseObject> Values { get; }
}
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> { }
公共接口不可测量
{
字符串名称{get;}
}
公共接口假定
{
无效添加(T obj);
IEnumerable值{get;}
}
公共阶层人士:无足轻重
{
公共字符串名称{get;set;}
公共整数{get;set;}
}
公车:不可测量
{
公共字符串名称{get;set;}
公共字符串模型{get;set;}
}
公共抽象类AbstractRepository:IRepository
其中T:不可测量
{
//和以前一样
字典值=新字典();
无效附加值(不可测量o)
{
添加(o.名称,o);
}
IEnumerable ValuesOfType()
{
返回value.values.OfType();
}
//使用泛型实现两个接口
公共无效添加(T obj)
{
附加值(obj);
}
公共IEnumerable值
{
得到
{
返回值softype();
}
}
}
公共类CarRepository:AbstractRepository{}
公共类PersonRepository:AbstractRepository{}

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

    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;
    }
}
类存储库:IRepository
其中T:不可测量
{
字典值=新字典();
无效附加值(TO)
{
添加(o.Name,o);
}
公共无效添加(T obj)
{
附加值(obj);
}
公共IEnumerable值
{
获取{返回值.values;}
}
}
工作类别
{
私有只读词典_repositories=新词典();
公共IRepository GetRepository()
其中T:不可测量
{
对象库;
if(!\u repositories.TryGetValue(类型(T),out repository))
{
repository=新存储库();
_储存库[类型(T)]=储存库;
}
返回(IRepository)存储库;
}
}
然后像这样使用它:

        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);
var unitOfWork=new unitOfWork();
unitOfWork.GetRepository().Add(新车{Name=“Audi”});
unitOfWork.GetRepository().Add(新车{Name=“BMW”});
foreach(unitOfWork.GetRepository()中的var car.Values)
控制台写入线(车名);

很明显,C#中的通用方法的设计不允许多个接口方法的通配符占位符解析为同一签名,因为在唯一的场景中,您希望所有这些方法的实现都是相同的。如果你想避免重复,你必须使用或类似的方法。但真的值得吗?对于更详细的示例IMO所提供的清晰性,有一些话要说。如果不可能改进我的第一个示例(不使其变得非常复杂/模糊),那么我不介意坚持使用它。只是我正计划对另外27个实体执行此操作,这是大量重复的代码。此解决方案的问题是它失去了一点类型安全性-例如,在使用之前,需要将Values方法转换为
IEnumerable
。它也不会根据您想要的类型返回单独的对象列表。与此相比,我更喜欢第一个版本,即使它的代码要多得多。我明白你的困境。有一种替代模式,我更新了答案。第二种解决方案也可以。我需要一点时间来看看结果如何。@Candide:他有这样一个基本的界面,
INameable
。这是一个很好的解决方案。我会试一试,看看结果如何。谢谢,这个解决方案很有效。最后,我通过使用组合而不是继承来访问基本存储库类型,对其进行了一些修改,但它仍然具有相同的效果。
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);