2011-05-10 52 views
2

我要实现以下结构:基本的C#接口问题

public interface IMyDbSet 
{ 
    IEnumerable<User> Users { get; } 
} 

public class ConcreteDbSet : IMyDbSet 
{ 
    DbSet<User> Users { get; set; } 
} 

虽然DbSet<T>IEnumerable<T>继承这不是possbile。

Visual Studio中的错误信息:

....不实现接口 成员 '......'。 '...'不能执行 '....',因为它没有匹配返回类型'....'的 。

是否有另一种方法来实现这样的结构,或者这是不可能的?

谢谢。

+2

你为什么要剪掉了错误信息的重要组成部分?这是告诉你到底是什么问题。 – 2011-05-10 09:55:39

+0

Cody Gray,错误应该是'ConcreteDbSet不实现接口成员IMyDbSet.Users。 ConcreteDbSet.Users不能实现IMyDbSet.Users,因为它没有匹配的返回类型IEnumerable '。 – 2011-05-10 09:59:42

+0

@Cody:对不起,我没有先检查你的声望。祝你有个好的一天。 – 2011-05-10 10:07:38

回答

8

最简单的方法是明确实现接口并从明确的Users属性返回隐式Users属性的值。

public interface IMyDbSet 
{ 
    IEnumerable<User> Users { get; } 
} 

public class ConcreteDbSet : IMyDbSet 
{ 
    IEnumerable<User> IMyDbSet.Users 
    { 
     get { return Users; } 
    } 

    DbSet<User> Users 
    { 
     get; set; 
    } 
} 
2

这是不可能的,因为谁调用IMyDbSet.Users预计将收到IEnumerable<User>这可能,但并不一定是DbSet<User>DBSet<T>IEnumerable<T>,但是IEnumerable<T>不是DbSet<T>

话虽这么说,没有什么可以阻止您返回DbSet<USer>实例作为IEnumerable<User>

1

要使用一个名为“return type covariance”的功能,这是不合法的(不幸)在C#编程语言。

在C++,Java或Eiffel(以及其他)的某些其他语言中,您可以在覆盖虚拟方法或实现接口时使用更具体的类型。

如果你正在处理接口,你可以使用已知的习惯用法(如弗洛里安提到的):你可以明确地实现你的接口,并添加另一个签名的方法。

public interface IMyDbSet 
{ 
    IEnumerable<User> Users { get; } 
} 

public class ConcreteDbSet : IMyDbSet 
{ 
    IEnumerable<User> IMyDbSet.Users {get {return Users;}} 

    public DbSet<User> Users { get; set; } 
} 

另一种选择 - 用户一般IMyDbSet<T>类似bool Equals(object rhs)System.Object和泛型类型安全接口[IEquatable<T>][2]

public interface IMyDbSet<T> where T : IEnumerable<User> 
{ 
    // Because T is IEnumerable<User> or one of it descendant 
    // this property is similar to IEnumerable<User> Users {get;} 
    T Users {get;} 
} 

// Now we're implementing not IMyDbSet interface itself 
// but we're IMyDbSet<IList<User>> instead. 
// Note you could use your own descendant for IEnumerable<User> here 
public class ConcreteDbSet : IMyDbSet<IList<User>> 
{ 
    public IList<User> Users {get; set;} 
} 


//... 
// and now you could use ConcreteDbSet following way: 
var set = new ConcreteDbSet(); 
IList<User> users = set.Users;