it-swarm.com.de

internes Mitglied in einer Schnittstelle

Ich habe eine Liste von Objekten, die eine Schnittstelle implementieren, und eine Liste dieser Schnittstelle:

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
}

Der vorherige Code wird nicht kompiliert, da der Compiler verlangt, dass alle Schnittstellenmitglieder öffentlich sind.

internal void Save(){

Aber ich möchte nicht zulassen, dass von außen mein DLL den ConcreteIAMspeichert, es sollte nur durch den MyListgespeichert werden.

Irgendwie kann ich das tun?

Update # 1 : Hallo zusammen, danke für die bisherigen Antworten, aber keine davon ist genau das, was ich brauche:

Die Schnittstelle muss öffentlich sein, da dies die Signatur ist, die der Client von außerhalb der DLL verwendet, zusammen mit IDund anderen Eigenschaften, die ich im Beispiel nicht geschrieben habe, um es einfach zu halten.

Andrew, ich glaube nicht, dass die Lösung eine Fabrik zum Erstellen eines anderen Objekts ist, das die Mitglieder eines IAMMitglieder + Speichern enthält. Ich denke immer noch nach ... Weitere Ideen?

33
fer

Ich denke, Sie verstehen nicht, wozu eine Schnittstelle dient. Schnittstelle ist ein Vertrag . Sie gibt an, dass sich ein Objekt auf bestimmte Weise verhält. Wenn ein Objekt eine Schnittstelle implementiert, können Sie sich darauf verlassen, dass alle Methoden der Schnittstelle implementiert sind.

Überlegen Sie sich nun, was passieren würde, wenn es eine gewünschte Schnittstelle gibt - öffentlich, aber mit einem internen Mitglied. Was würde das bedeuten Ein externes Objekt könnte nur die öffentlichen Methoden implementieren, nicht jedoch die internen. Wenn Sie ein solches externes Objekt erhalten, können Sie nur die öffentlichen Methoden aufrufen, nicht aber die internen, da das Objekt es nicht implementieren konnte. Mit anderen Worten - der Vertrag würde nicht erfüllt werden. Nicht alle Methoden würden implementiert.

Ich denke, dass die Lösung in diesem Fall darin besteht, Ihre Schnittstelle in zwei Teile zu teilen. Eine Schnittstelle wäre öffentlich, und das würden Ihre externen Objekte implementieren. Die andere Schnittstelle wäre intern und würde Ihre Save() und andere interne Methoden enthalten. Vielleicht könnte diese zweite Schnittstelle sogar von der ersten erben. Ihre eigenen internen Objekte würden dann beide Schnittstellen implementieren. Auf diese Weise können Sie sogar zwischen externen Objekten (Objekten ohne interne Schnittstelle) und internen Objekten unterscheiden.

40
Vilx-

Erstellen Sie eine andere Schnittstelle, die intern ist, und verwenden Sie die explizite Implementierung für die Methode.

internal interface InternalIAM
{
    void Save();
}

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

Ich denke nicht, dass Sie hier eine Schnittstelle verwenden sollten. Vielleicht sollten Sie eine abstrakte Basis verwenden, etwa:

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
    }
}

Erlaubt dir immer noch das zu tun:

public class AMList : List<AM>
{
    public void SaveItems()
    {
        foreach (var item in this)
        {
            item.Save();
        }
    }
}
9
Nathan W

Ich denke, das Beste wäre, die internen und öffentlichen Mitglieder in zwei getrennte Schnittstellen zu unterteilen. Wenn Sie die Schnittstellen erben, können Sie die Mitglieder weiterhin öffentlich deklarieren. Die Sichtbarkeit der internen Mitglieder wird jedoch von der Sichtbarkeit der Schnittstelle selbst bestimmt.

using System;

public interface IPublic
{
    void Public();
}

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

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

    public void Public() { }
}
7
Andrew Hare

Es ist genau das, worüber ich in meinem Artikel spreche Freunde und Mitglieder der internen Schnittstelle kostenlos mit Codierung für Schnittstellen .

Die Essenz aus dem Artikel

public class Internal
{
    internal Internal() { }
}

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

Ab sofort kann nur Ihre Assembly die Save()-Methode aufrufen, da eine Instanz der Internal-Klasse nur von Ihrer Assembly erstellt werden kann.

3
Reuven Bass

Warum verwenden Sie keine inneren Klassen, um die Zugänglichkeit Ihrer Methoden zu kontrollieren?

Beispiel:

Deine Hauptversammlung

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

Deine sekundäre Versammlung

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

Mit diesem Muster können Sie weiterhin die Save()-Methode in anderen Assemblys implementieren, aber nur ItemCollection, die innere Klasse von Item, kann es aufrufen. Brillant, nicht wahr?

1
lubos hasko

Wenn Sie nicht möchten, dass externe Anrufer Ihre Save () - Methode aufrufen können, können Sie die gesamte concreteIAM-Klasse intern machen.

Wenn Sie möchten, dass die Klasse public ist, nicht aber die Schnittstelle, können Sie die gesamte Schnittstelle intern machen. Ich denke, eine interne Schnittstelle kann zu einer öffentlichen Klasse hinzugefügt werden (aber ich habe es nicht probiert ...)

1
Brannon

Vielleicht möchten Sie das Speichern Ihrer Elemente in andere Klassen Ihrer Assembly unterteilen:

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)
    }
  }
}
1
Andrew Kennan

Interface-Mitglieder sollen öffentlich sein ... alles andere und Sie sollten denken, wenn Sie etwas anderes brauchen. In diesem Fall du

  • möchte, dass Save ein Mitglied der Benutzeroberfläche ist
  • sie möchten, dass Save nur über eine andere Klasse namens MyList erlaubt wird, die sich in derselben Assembly befindet
  • verhindern, dass Save extern aufgerufen wird (von anderen Klassen außerhalb der übergeordneten Assembly)

Abgesehen von Design-Gedanken können Sie dies über die Implementierung der expliziten Schnittstelle tun.

    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 ist intern und außerhalb der übergeordneten Assembly nicht verfügbar. Da es explizit implementiert ist, kann es nicht ohne IPersist-Referenz aufgerufen werden.

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

Update Aus Ihrer letzten Antwort haben wir mehr Einschränkungen. Die Schnittstelle muss öffentlich sein, sie sollte die Save-Methode enthalten, die nicht öffentlich verfügbar sein sollte. Ich würde sagen, zurück zum Zeichenbrett ... etwas scheint nicht richtig zu sein. IMHO Sie können dies nicht mit einer einzigen Schnittstelle tun. Wie wäre es mit der Aufteilung in 2 Schnittstellen, die öffentliche und die interne Schnittstelle?

1
Gishu

Gehen Sie mit zwei Schnittstellen:

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
}

Die Implementierung von Save () muss explizit sein, damit Clients sie nicht aufrufen können.

0
MZywitza

Ich hatte eine ähnliche Situation und dachte, das könnte helfen. (nicht sicher, ob dies zu diesem Zeitpunkt nicht erforderlich ist oder nicht)

Dies ist ein legitimer Fall für mich: Falls angenommen wird, es gibt eine Schnittstelle mit einer API, die intern zu DLL ist, und auf einige API kann von außerhalb der DLL zugegriffen werden. Da Schnittstelle eine abstrakte Klasse ist, können Sie sie nicht als Schnittstelle definieren, sondern als abstrakte Klasse.

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
}
0
Rishi Prasad