嵌套接口的替代方案(C#中不可行)

25

在这种情况下,我主要使用接口作为对对象不可变实例的句柄。问题是C#中不允许嵌套接口。以下是代码:

public interface ICountry
{
    ICountryInfo Info { get; }

    // Nested interface results in error message:
    // Error    13  'ICountryInfo': interfaces cannot declare types
    public interface ICountryInfo
    {
        int Population { get; }
        string Note { get; }
    }
}


public class Country : ICountry
{
    CountryInfo Info { get; set; }

    public class CountryInfo : ICountry.ICountryInfo
    {
        int Population { get; set; }
        string Note { get; set; }
        .....
    }
    .....
}

我正在寻找一种替代方案,有人能提供解决方案吗?


1
你想让 ICountryInfo 嵌套的原因是什么? - AakashM
4
是的,该应用程序包含100多个类,其中许多嵌套类具有相同的名称。如果我保留这种设置,它会更加清晰。至于使用接口,那是获取它们的不可变副本的一种方法。一旦对象被实例化,主要应用程序大多数情况下使用依赖注入模式处理其对应接口。 - ericdes
5个回答

21

VB.NET 是支持这个的。所以,你可以只使用 VB.NET 定义接口来创建一个 VB.NET 程序集:

Public Interface ICountry
  ReadOnly Property Info() As ICountryInfo
    
  Public Interface ICountryInfo
    ReadOnly Property Population() As Integer
    ReadOnly Property Note() As String
  End Interface
End Interface

在实现方面,C#不支持协变返回类型,因此您必须像这样声明您的类:

public class Country : ICountry {
  // this property cannot be declared as CountryInfo
  public ICountry.ICountryInfo Info { get; set; }
  
  public class CountryInfo : ICountry.ICountryInfo {
    public string Note { get; set; }
    public int Population { get; set; }
  }
}

3
您可以像这样使用命名空间:
namespace MyApp
{
    public interface ICountry { }

    namespace Country
    {
        public interface ICountryInfo { }
    }
}

然后,在MyApp命名空间中,您可以使用接近您要求的Country.ICountryInfo。此外,using alias有助于使代码更清晰。


2

如果最终目标是与依赖注入一起使用,那么将它们互相注入而不是嵌套有什么问题呢?

public interface ICountry
{
    ICountryInfo Info { get; }
}

public interface ICountryInfo
{
    int Population { get; set; }
    string Note { get; set; }
}

并实现为:

public class Country : ICountry
{
    private readonly ICountryInfo _countryInfo;

    public Country(ICountryInfo countryInfo)
    {
        _countryInfo = countryInfo;
    }

    public ICountryInfo Info
    {
        get { return _countryInfo; }
    }
}

public class CountryInfo : ICountryInfo
{
    public int Population { get; set; }
    public string Note { get; set;}
}

当你设置ICountry和ICountryInfo的绑定之后,CountryInfo将会在注入Country时被注入。

如果你想要限制绑定,只在Country中注入CountryInfo而不注入其他地方,可以在Ninject中进行如下设置:

Bind<ICountry>().To<Country>();
Bind<ICountryInfo>().To<CountryInfo>().WhenInjectedInto<Country>();

1

这样做完全没问题,不需要嵌套:

public interface ICountry
{
    ICountryInfo Info { get; }
}

public interface ICountryInfo
{
    int Population { get; }
    string Note { get; }
}

8
是的,但这样做违背了我创建嵌套类的原因。ICountryInfo在除了ICountry内部以外的任何其他地方都不应具有意义。 - ericdes
15
我同意 @ericdes 的观点。这是 C# 无法解决的情况。 - user297691
没有嵌套接口的可能性会使作用域混杂不必要的名称。类型(接口)可能具有相似的名称,但根据其上下文提供不同的服务。 - Werner Erasmus

1
如果ICountryInfo没有存在于ICountry之外的理由,那么为什么不把ICountryInfo的属性放在ICountry中,并放弃嵌套接口的想法呢?
对我来说,一个没有自己意义的接口,如果没有被类实现,那么它本身就是无用的。

+1 我完全同意。在这个例子中似乎没有必要有一个 ICountryInfo。 - Ian
我刚从一个包含超过100个类和许多嵌套类的应用程序中提取了示例代码。如果保留嵌套类的设置,代码会更加清晰。至于使用接口,则是获取它们的不可变副本的一种方式。一旦对象被实例化,主要应用程序大多数情况下会使用依赖注入模式处理它们相应的接口。我不想以导致代码不实用的方式修改嵌套结构。 - ericdes
10
虽然我同意所给出的示例并不合理,最好将其表达为单一接口,但这并不意味着这个想法是无效的。例如,如果ICountry接口具有ICountryInfo对象的集合而不仅仅是一个对象,那么将其展开为单一接口显然是行不通的。 ;) - CptRobby

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接