我有一个实现接口的对象列表,以及该接口的列表:
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
成员+保存的对象。我还在想......还有其他想法吗?
答案 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)
如果您不希望外部呼叫者能够调用您的Save()方法,为什么不让整个concreteIAM类内部?
或者,如果您希望类是public,而不是接口,请将整个接口设置为内部。我认为内部接口可以添加到公共类(但我还没有尝试过......)
答案 6 :(得分: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)
}
}
}
答案 7 :(得分:1)
接口成员应该是公开的...其他任何东西你应该考虑是否需要别的东西。在这种情况下,你
将设计思想放在一边,可以通过显式接口实现来实现。
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个接口,公共接口和内部接口?
答案 8 :(得分: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
可以调用它。太棒了,不是吗?
答案 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 :(得分: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()
变为有效 {{1 }}。
这在概念上与 this answer 中提出的解决方案非常相似,但无需声明第二个接口。
答案 12 :(得分:-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
}