简体   繁体   English

基本的C#接口问题

[英]Basic C# Interfaces Question

I want to to implement following structure: 我想实现以下结构:

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

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

Although DbSet<T> inherits from IEnumerable<T> this is not possbile. 虽然DbSet<T>继承自IEnumerable<T>但这不可能。

Visual Studio error message: Visual Studio错误消息:

.... does not implement interface member '....'. ....没有实现接口成员'....'。 '...' cannot implement '....' because it does not have the matching return type of '....'. '...'无法实现'....',因为它没有匹配的返回类型'....'。

Is there another way to implement such a structure or is this not possible at all? 有没有其他方法来实现这样的结构或者这根本不可能?

Thanks. 谢谢。

The easiest way would be to implement the interface explicitely and return the value of the implicit Users property from the explicit Users property. 最简单的方法是明确地实现接口,并从显式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; 
    }
}

It is impossible because whoever invokes IMyDbSet.Users expects to receive IEnumerable<User> which may but does not have to be DbSet<User> . 这是不可能的,因为无论谁调用IMyDbSet.Users希望接收IEnumerable<User> ,它可能但不一定是DbSet<User> DBSet<T> is IEnumerable<T> , but IEnumerable<T> is not DbSet<T> . DBSet<T>IEnumerable<T> ,但IEnumerable<T>不是DbSet<T>

That being said nothing prevents you from returning DbSet<USer> instance as IEnumerable<User> DbSet<USer>什么阻止你将DbSet<USer>实例作为IEnumerable<User>

The feature that you want to use called " return type covariance " and this is not legal (unfortunately) in C# programming language. 您要使用的功能称为“ 返回类型协方差 ”,这在C#编程语言中是不合法的(不幸的是)。

In some other language like C++, Java or Eiffel (and some other) you could use more concrete type during overriding virtual method or implement interface. 在其他语言中,如C ++,Java或Eiffel(以及其他一些语言),您可以在覆盖虚拟方法或实现接口时使用更具体的类型。

If you're dealing with interface you could use known idiom (as Florian mentioned): you could implement your interface explicitly and add another method with another signature. 如果您正在处理接口,您可以使用已知的习惯用法(如Florian所提到的):您可以显式实现您的接口并添加另一个带有另一个签名的方法。

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

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

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

Another option - user generic IMyDbSet<T> similarly to bool Equals(object rhs) from System.Object and generic typesafe interface [IEquatable<T>][2] : 另一个选项 - 用户通用IMyDbSet<T>类似于来自System.Object bool Equals(object rhs)和泛型类型安全接口[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;

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

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