43

我有一个实现接口的对象列表,以及该接口的列表:

public interface IAM
{
    int ID { get; set; }
    void Save();
}

public class concreteIAM : IAM
{
     public int ID { get; set; }
     internal void Save(){
     //save the object
     }

    //other staff for this particular class
}

public class MyList : List<IAM>
{
    public void Save()
    {
        foreach (IAM iam in this)
        {
            iam.Save();
        }
    }

    //other staff for this particular class
}

前面的代码无法编译,因为编译器要求所有接口成员都是公共的。

internal void Save(){

但我不想让我的 DLL 外部ConcreteIAMMyList.

有什么办法可以做到这一点?

更新#1:大家好,感谢到目前为止的答案,但它们都不是我所需要的:

该接口需要是公共的,因为它是来自 dll 外部的客户端将使用的签名,以及ID我在示例中不费心编写的其他属性以保持简单。

安德鲁,我不认为解决方案是创建一个工厂来创建另一个包含IAM成员+保存的对象。我还在想……还有其他的想法吗?

4

13 回答 13

50

我认为您不了解接口的用途。接口是一个契约。它指定对象以某种方式运行。如果一个对象实现了一个接口,这意味着你可以依赖它,它实现了接口的所有方法。

现在,考虑一下如果有一个像您要求的界面会发生什么 - 公开,但只有一个内部成员。那意味着什么?外部对象只能实现公共方法,而不能实现内部方法。当您获得这样一个外部对象时,您将只能调用公共方法,而不能调用内部方法,因为该对象无法实现它。换句话说 -合同不会被履行。并不是所有的方法都会被实现。

我认为这种情况下的解决方案是将您的界面一分为二。一个接口将是公共的,这就是您的外部对象将实现的。另一个接口将是内部的,将包含您的Save()和其他内部方法。也许这第二个接口甚至可以从第一个继承。然后,您自己的内部对象将实现这两​​个接口。这样,您甚至可以区分外部对象(没有内部接口的对象)和内部对象。

于 2008-12-15T09:55:49.673 回答
36

创建另一个内部接口,并为该方法使用显式实现。

internal interface InternalIAM
{
    void Save();
}

public class concreteIAM : InternalIAM
{
    void InternalIAM.Save()
    {
    }
}
于 2008-12-15T10:23:37.933 回答
9

我认为最好的办法是将内部成员和公共成员分成两个独立的接口。如果您继承接口,您仍然可以公开声明成员,但内部成员的可见性将由接口本身的可见性决定。

using System;

public interface IPublic
{
    void Public();
}

internal interface IInternal : IPublic
{
    void Internal();
}

public class Concrete : IInternal
{
    public void Internal() { }

    public void Public() { }
}
于 2008-12-15T14:15:10.883 回答
8

我认为您不应该在这里使用界面。也许您应该使用抽象基础,例如:

public abstract class AM
{
    public int ID { get; set; }
    internal abstract void Save();
}

public class concreteIAM : AM
{
    internal override void Save()
    {
        //Do some save stuff
    }
}

仍然允许您这样做:

public class AMList : List<AM>
{
    public void SaveItems()
    {
        foreach (var item in this)
        {
            item.Save();
        }
    }
}
于 2008-12-15T04:18:05.860 回答
4

这正是我在我的文章Friends and internal interface members at no cost with coding to interfaces中所说的。

文章的精华

public class Internal
{
    internal Internal() { }
}

public interface IAM
{
    int ID { get; set; }
    void Save(Internal access);
}

从现在开始,只有您的程序集可以调用该Save()方法,因为Internal类的实例只能由您的程序集创建。

于 2012-06-21T19:35:21.627 回答
1

如果您不希望外部调用者能够调用您的 Save() 方法,为什么不将整个具体IAM 类设为内部?

或者,如果您希望类公开,而不是接口,则将整个接口设为内部。我认为可以将内部接口添加到公共类中(但我没有尝试过...)

于 2008-12-15T05:01:57.800 回答
1

也许您想将项目的保存分离到您的程序集内部的一组不同的类中:

internal interface IAMSaver { void Save(IAM item); }

internal class AMSaverFactory {
  IAMSaver GetSaver(Type itemType) { ... }
}

public class MyList : List<IAM>
{
  public void Save()
  {
    foreach (IAM itemin this)
    {
      IAMSaver saver = SaverFactory.GetSaver(item.GetType());
      saver.Save(item)
    }
  }
}
于 2008-12-15T05:16:31.470 回答
1

接口成员应该是公开的......其他任何东西,你应该考虑是否需要其他东西。在这种情况下,您

  • 希望保存成为界面成员
  • 希望 Save 仅允许通过位于同一程序集中的另一个名为 MyList 的类
  • 禁止 Save 被外部调用(从父程序集之外的其他类)

抛开设计思想,您可以通过显式接口实现来做到这一点。

    internal interface IPersist
    {
        void Save();
    }
    public class Concrete : IPersist
    {
        void IPersist.Save()
        {
            Console.WriteLine("Yeah!");
        }
    }

// Mylist.cs in the same assembly can still call save like
public void SaveItems()
    {
        foreach (IPersist item in this)
        {
            item.Save();
        }
    }

IPersist 是内部的,在父程序集之外不可用,并且由于它是显式实现的,因此如果没有 IPersist 引用就无法调用它。

new Concrete().Save();     // doesn't compile. 'Concrete' does not contain a definition for 'Save'

更新根据您的最新回复,我们有更多限制。接口必须是公共的,它应该包含 Save 方法,它不应该是公开的。我会说回到绘图板......似乎有些不对劲。恕我直言,您不能使用单个界面执行此操作。拆分成两个接口,公共接口和内部接口怎么样?

于 2008-12-15T05:31:25.900 回答
1

使用两个接口:

public interface IAM
{
        int ID { get; set; }
}


internal interface IAMSavable
{
        void Save();
}

public class concreteIAM : IAM, IAMSavable
{
         public int ID{get;set;}
         public void IAMSavable.Save(){
         //save the object
         }

        //other staff for this particular class
}

public class MyList : List<IAM>
{
        public void Save()
        {
                foreach (IAM iam in this)
                {
                        ((IAMSavable)iam).Save();
                }
        }

        //other staff for this particular class
}

Save() 的实现必须明确以防止客户端调用它。

于 2008-12-15T10:04:10.700 回答
1

为什么不使用内部类来控制方法的可访问性?

例子:

您的主要装配体

public abstract class Item
{
    public int ID { get; set; }
    protected abstract void Save();

    public class ItemCollection : List<Item>
    {
        public void Save()
        {
            foreach (Item item in this) item.Save();
        }
    }
}

您的二次装配

public sealed class NiceItem : Item
{
    protected override void Save()
    {
        // do something
    }
}

这种模式仍然允许您Save()在其他程序集中实现方法,但只有ItemCollection内部类Item可以调用它。很棒,不是吗?

于 2008-12-15T10:07:39.930 回答
0

那这个呢?

public interface IAM
{
    int ID { get; set; }
    internal void Save();
}

public class concreteIAM : IAM
{
     public int ID { get; set; }
     void IAMSavable.Save() {
         //save the object
     }
}

您可以将接口的成员声明为内部的,但是当您在类中实现它时,您只有两个选择:将其声明为公共或显式接口实现。通过将其实现为显式接口实现,如示例代码中所做的那样,Save()只能通过强制转换concreteIAM为访问IAM,因此Save()变为有效internal

这在概念上与此答案中提出的解决方案非常相似,但是无需声明第二个接口。

于 2021-06-28T17:15:37.870 回答
0

我有类似的情况,并认为这会有所帮助。(不确定此时是否不需要)

这对我来说是一个合法的案例:假设有一个接口具有一些在 DLL 内部的 API,并且可以从 DLL 外部访问一些 API。由于接口是一个抽象类,因此您可以定义为抽象类,而不是定义为接口。

using System.Collections.Generic;

public abstract class IAM
{
    int ID { get; set; }
    internal abstract void Save();
}

public class concreteIAM : IAM
{
    public int ID { get; set; }
    internal override void Save()
    {
        //save the object
    }

    //other staff for this particular class
}

public class MyList : List<IAM>
{
     internal void Save()
    {
        foreach (IAM iam in this)
        {
            iam.Save();
        }
    }

    //other staff for this particular class
}
于 2018-10-22T17:24:43.663 回答
-2

我在这里想知道同样的问题,偶然发现了这个问题......

当我想到这一点时,我明白我首先不需要接口中的内部方法。

我可以通过我的具体类访问它,并将合同留给外部代码。

在您的示例中:

    public interface IAM
    {
            int ID { get; set; }
    }

    public class concreteIAM : IAM
    {
             public int ID{get;set;}
             internal void Save(){
             //save the object
             }

            //other staff for this particular class
    }

    public class MyList : List<IAM>
    {
            public void Save()
            {
                    foreach (concreteIAM iam in this)
                    {
                            iam.Save();
                    }
            }
            //other staff for this particular class
    }
于 2012-01-11T17:12:44.730 回答