接口中的内部成员

时间:2008-12-15 04:13:49

标签: c# interface concreteclass

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

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外部保存ConcreteIAM,只应通过MyList保存。

有什么办法吗?

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

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

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

12 个答案:

答案 0 :(得分:39)

我认为您无法理解界面的用途。界面是合同。它指定对象以某种方式运行。如果一个对象实现了一个接口,那就意味着你可以依赖它实现所有接口的方法。

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

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

答案 1 :(得分:25)

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

internal interface InternalIAM
{
    void Save();
}

public class concreteIAM : InternalIAM
{
    void InternalIAM.Save()
    {
    }
}

答案 2 :(得分:9)

我认为你不应该在这里使用界面也许你应该使用类似的抽象基础。:

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();
        }
    }
}

答案 3 :(得分:7)

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

using System;

public interface IPublic
{
    void Public();
}

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

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

    public void Public() { }
}

答案 4 :(得分:3)

这正是我在文章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类的实例只能由程序集创建。

答案 5 :(得分: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可以调用它。太棒了,不是吗?

答案 6 :(得分:1)

如果您不希望外部呼叫者能够调用您的Save()方法,为什么不让整个concreteIAM类内部?

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

答案 7 :(得分: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)
    }
  }
}

答案 8 :(得分:1)

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

  • 想要保存为接口成员
  • 想要保存只允许通过另一个名为MyList的类(位于同一个程序集中)
  • 禁止从外部调用保存(从父程序集外的其他类)

将设计思想放在一边,可以通过显式接口实现来实现。

    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方法,该方法不应公开。 我会说回到绘图板上......似乎不对劲。恕我直言你不能用一个界面做到这一点。如何分成2个接口,公共接口和内部接口?

答案 9 :(得分:0)

使用两个界面:

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()的实现必须是显式的,以防止客户端调用它。

答案 10 :(得分:0)

我有类似的情况,并认为这可以有所帮助。 (不确定目前是否不需要)

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

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
}

答案 11 :(得分:-2)

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

正如我想的那样,我知道我首先不需要接口中的内部方法。

我可以通过我的Concrete Class访问它, 并留下合同作为外线代码。

在你的例子中:

    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
    }