una que puede programacion interfaz interfaces instancia implementacion herencia heredar declaracion declara cómo crear clase caracteristicas c# interface concreteclass

c# - que - miembro interno en una interfaz



que es una interfaz en programacion (11)

Tengo una lista de objetos que implementan una interfaz y una lista de esa interfaz:

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 }

El código anterior no se compila porque el compilador requiere que todos los miembros de la interfaz sean públicos.

internal void Save(){

Pero no quiero permitir que desde fuera de mi DLL guarde el ConcreteIAM , solo debe guardarse a través de MyList .

Alguna forma de hacer esto?

Actualización n. ° 1 : Hola a todos, gracias por las respuestas hasta ahora, pero ninguno de ellos es exactamente lo que necesito:

La interfaz debe ser pública porque es la firma que utilizará el cliente que no pertenece a la dll, junto con la ID y otras propiedades que no me molesté en escribir en el ejemplo para mantenerlo simple.

Andrew, no creo que la solución sea crear una fábrica para crear otro objeto que contenga a los miembros de IAM + Guardar. Todavía estoy pensando ... ¿Alguna otra idea?


Tal vez desee separar el guardado de sus artículos en un conjunto diferente de clases que son internas de su conjunto:

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


¿Por qué no usas clases internas para controlar la accesibilidad de tus métodos?

Ejemplo:

Su ensamblaje principal

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

Su ensamblaje secundario

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

Este patrón aún le permitirá implementar el método Save() en otros ensambles, pero solo ItemCollection que es clase interna de Item puede ItemCollection . Brillante, ¿no?


Creo que no entiendes para qué es una interfaz. La interfaz es un contrato . Especifica que un objeto se comporta de cierta manera. Si un objeto implementa una interfaz, significa que puede confiar en que tiene implementados todos los métodos de la interfaz.

Ahora, considere qué pasaría si hubiera una interfaz como la que está pidiendo, pública, pero con un miembro interno. ¿Qué significa eso? Un objeto externo podría implementar solo los métodos públicos, pero no el interno. Cuando obtendría un objeto externo de este tipo, podría llamar solo a los métodos públicos, pero no a los internos, porque el objeto no podría implementarlo. En otras palabras, el contrato no se cumpliría. No todos los métodos se implementarán.

Creo que la solución en este caso es dividir tu interfaz en dos. Una interfaz sería pública, y eso es lo que implementarían sus objetos externos. La otra interfaz sería interna y contendría su Save() y otros métodos internos. Quizás esta segunda interfaz podría incluso heredarse de la primera. Sus propios objetos internos implementarían ambas interfaces. De esta forma, incluso podría distinguir entre objetos externos (los que no tienen la interfaz interna) y objetos internos.


Ir con dos 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 }

La implementación de Save () debe ser explícita para evitar que los clientes lo llamen.


Se supone que los miembros de la interfaz son públicos ... cualquier otra cosa y deberías pensar si necesitas algo más. En este caso, tu

  • quiere que Save sea un miembro de la interfaz
  • quiere que Guardar solo se permita a través de otra clase llamada MyList que se encuentra en el mismo ensamblaje
  • no permite que Save se llame externamente (desde otras clases fuera del ensamblaje principal)

Dejando de lado los pensamientos de diseño, puede hacer esto a través de la Implementación explícita de interfaz.

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 es interno, no está disponible fuera del ensamblaje principal y, dado que está implementado explícitamente, no se puede invocar sin una referencia de IPersist.

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

Actualización Desde su última respuesta, tenemos más restricciones. La interfaz debe ser pública, debe contener el método Guardar, que no debe estar disponible públicamente. Yo diría que volver al tablero de dibujo ... algo no parece correcto. En mi humilde opinión, no puede hacer esto con una sola interfaz. ¿Qué tal dividir en 2 interfaces, la pública y la interna?


Cree otra interfaz que sea interna y use implementación explícita para el método.

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


Creo que lo mejor sería dividir a los miembros internos y públicos en dos interfaces separadas. Si hereda las interfaces, puede declarar públicamente a los miembros, pero la visibilidad de los miembros internos dependerá de la visibilidad de la interfaz.

using System; public interface IPublic { void Public(); } internal interface IInternal : IPublic { void Internal(); } public class Concrete : IInternal { public void Internal() { } public void Public() { } }


No creo que debas usar una interfaz aquí, tal vez deberías estar usando una base abstracta como:

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

Todavía te permitirá hacer esto:

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


Si no desea que los llamadores externos puedan llamar a su método Save (), ¿por qué no hacer que toda la clase concreteIAM sea interna?

O bien, si desea que la clase sea pública, pero no la interfaz, haga que toda la interfaz sea interna. Creo que se puede agregar una interfaz interna a una clase pública (pero no lo he intentado ...)



Me preguntaba sobre el mismo problema aquí, y tropecé con esta pregunta ...

Mientras pensaba en esto, entendí que no necesito el método interno en la interfaz en primer lugar.

Puedo acceder a él a través de mi Concrete Class y dejar el contrato para el código externo.

En tu ejemplo:

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 }