internal member in an interface

2020-08-09 05:13发布

I have a list of objects implementing an interface, and a list of that interface:

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
}

The previous code doesn't compile because the compiler requires all the interface members to be public.

internal void Save(){

But i don't want to allow the from outside my DLL to save the ConcreteIAM, it only should be saved through the MyList.

Any way to do this?

Update#1: Hi all, thanks for the answers so far, but none of them is exactly what i need:

The interface needs to be public because it is the signature the client from outside the dll will use, along with ID and other properties i didn't bother to write in the example to keep it simple.

Andrew, I don't think the solution is create a factory to create another object that will contain the IAM members + Save. I am still thinking... Any other ideas?

12条回答
地球回转人心会变
2楼-- · 2020-08-09 05:19

It is exactly what I am talking about in my article Friends and internal interface members at no cost with coding to interfaces.

The essence from the article

public class Internal
{
    internal Internal() { }
}

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

From now one only your assembly can call the Save() method, since an instance of the Internal class can only be created by your assembly.

查看更多
淡お忘
3楼-- · 2020-08-09 05:21

Interface members are supposed to be public.. anything else and you should be thinking if you need something else. In this case, you

  • want Save to be an interface member
  • want Save to be only allowed via another class called MyList which lies in the same assembly
  • disallow Save from being called externally (from other classes outside the parent assembly)

Keeping design thoughts aside, you could do this via Explicit Interface Implementation.

    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 is internal, not available outside the parent assembly and since it is explicitly implemented, it cannot be called without an IPersist reference.

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

Update From your latest response, we have more constraints. The Interface must be public, it should contain the Save method, which shouldn't be publicly available. I'd say go back to the drawing board... something doesn't seem right. IMHO You can't do this with a single interface. How about splitting into 2 interfaces, the public one and the internal one?

查看更多
beautiful°
4楼-- · 2020-08-09 05:21

Go with two interfaces:

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
}

The implementation of Save() must be explicit to prevent clients calling it.

查看更多
女痞
5楼-- · 2020-08-09 05:22

I think the best thing to do would be to break the internal and public members into two separate interfaces. If you inherit the interfaces you can still declare the members publicly but the visibility of the internal members will be dictated by the visibility of the interface itself.

using System;

public interface IPublic
{
    void Public();
}

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

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

    public void Public() { }
}
查看更多
对你真心纯属浪费
6楼-- · 2020-08-09 05:28

If you don't want external callers to be able to call your Save() method, why not make the whole concreteIAM class internal?

Or, if you want the class public, but not the interface, make the whole interface internal. I think an internal interface can be added to a public class (but I haven't tried it...)

查看更多
劳资没心,怎么记你
7楼-- · 2020-08-09 05:29

I think you don't understand what an interface is for. Interface is a contract. It specifies that an object behaves in a certain way. If an object implements an interface, it means that you can rely on it that it has all the interface's methods implemented.

Now, consider what would happen if there was an interface like you're asking for - public, but with one internal member. What would that mean? An external object could implement only the public methods, but not the internal one. When you would get such an external object, you would be able to call only the public methods, but not the internal one, because the object couldn't implement it. In other words - the contract would not be fulfilled. Not all of the methods would be implemented.

I think that the solution in this case is to split your interface in two. One interface would be public, and that's what your external objects would implement. The other interface would be internal and would contain your Save() and other internal methods. Perhaps this second interface could even inherit from the first. Your own internal objects would then implement both interfaces. This way you could even distinguish between external objects (ones that don't have the internal interface) and internal objects.

查看更多
登录 后发表回答