Pregunta

Estoy tratando de acceder a un método marcado como interno en la clase principal (en su propio ensamblaje) en un objeto que hereda del mismo padre.

Déjame explicar lo que estoy tratando de hacer ...

Quiero crear clases de servicio que devuelvan a IEnumberable con una lista subyacente a las clases no de servicio (por ejemplo, la interfaz de usuario) y opcionalmente devuelvan un IEnumerable con un IQUERABLE subyacente a otros servicios.

Escribí algún código de muestra para demostrar lo que estoy tratando de lograr, que se muestra a continuación. El ejemplo no es la vida real, así que recuerde que al comentar.

Todos los servicios heredarían de algo como esto (solo un código relevante que se muestra):

public class ServiceBase<T>
{
    protected readonly ObjectContext _context;
    protected string _setName = String.Empty;

    public ServiceBase(ObjectContext context)
    {
        _context = context;
    }

    public IEnumerable<T> GetAll()
    {
        return GetAll(false);
    }

    //These are not the correct access modifiers.. I want something
    //that is accessible to children classes AND between descendant classes
    internal protected IEnumerable<T> GetAll(bool returnQueryable)
    {
        var query = _context.CreateQuery<T>(GetSetName());
        if(returnQueryable)
        {
            return query;
        }
        else
        {
            return query.ToList();
        }
    }

    private string GetSetName()
    {
        //Some code...
        return _setName;
    }



}

Los servicios heredados se verían así:

public class EmployeeService : ServiceBase<Employees>
{
    public EmployeeService(ObjectContext context)
        : base(context)
    {

    }

}

public class DepartmentService : ServiceBase<Departments>
{
    private readonly EmployeeService _employeeService;

    public DepartmentService(ObjectContext context, EmployeeService employeeService) : base(context)
    {
        _employeeService = employeeService;
    }

    public IList<Departments> DoSomethingWithEmployees(string lastName)
    {
        //won't work because method with this signature is not visible to this class
        var emps = _employeeService.GetAll(true);

        //more code...
    }
}

Debido a que la clase matriz vive es reutilizable, viviría en una asamblea diferente al de los servicios infantiles. Dado que Getall (Bool ReturnQueryable) está marcado interno, los niños no podrían ver el método Getall (Bool) de los demás, solo el método público getall ().

Sé que puedo agregar un nuevo método interno GetAll a cada servicio (o tal vez una clase principal intermedia dentro del mismo ensamblaje) para que cada servicio infantil dentro del ensamblaje pueda ver el método del otro; Pero parece innecesario ya que la funcionalidad ya está disponible en la clase principal.

Por ejemplo:

    internal IEnumerable<Employees> GetAll(bool returnIQueryable)
    {
        return base.GetAll(returnIQueryable);
    }

Esencialmente, lo que quiero es que los servicios puedan acceder a otros métodos de servicio como IQueryable para que puedan refinar aún más los resultados no comprometidos, mientras que todos los demás obtienen listas antiguas.

¿Algunas ideas?

EDITAR

Sabes qué, me divertí jugando un pequeño código de golf con esto ... pero en última instancia no podría usar este esquema de todos modos porque paso interfaces, no clases.

Entonces, en mi ejemplo, GetAll (Bool Returniqueryable) no estaría en la interfaz, lo que significa que tendría que hacer un casting, lo que va en contra de lo que estoy tratando de lograr.

No estoy seguro de si tenía un pedo cerebral o si estaba demasiado emocionado tratando de obtener algo que pensé que era bueno funcionar. De cualquier manera, gracias por las respuestas.

¿Fue útil?

Solución

¿Qué hay de malo en la respuesta obvia de hacer público el método?

La accesibilidad no es segura de todos modos, por lo que las "personas malvadas" podrían usar la reflexión para evitar cualquier modificador que pongas. Y dado que desea llamar a estos métodos de clases de "hermanos" no relacionadas, deben ser públicos, ya que no hay un modificador de accesibilidad de "hermano".

Sugerencia alternativa: aplique el [assembly:InternalsVisibleTo("SomeOtherAssembly")] Atributo para otorgar otros asambleas de dominio comercial acceso a los miembros internos.

Tenga en cuenta que esto agrega una carga de mantenimiento (si cambia el nombre o agrega ensamblajes), usa "cadenas mágicas" y niega el significado original de interno (ya que todos los miembros internos ahora también serán visibles para estos otros ensamblajes).

Otros consejos

Cuando sus clases descendientes vivirían en la misma asamblea, esto sería más fácil. Sin embargo, el siguiente 'truco' también funciona cuando sus clases viven en asambleas separadas (cambiando la interfaz internal palabra clave para public), pero solo evitaría que el método se llame cuando el objeto no está fundido. Por ejemplo, lanzar un InheritedClass Objetar a un IBaseInterface permitiría que cualquiera llame al GetValue método. Esto es algo que realmente no puede evitar, porque incluso si hay alguna combinación de palabras clave que puedan hacer lo que desea, alguien aún podría llamar a los métodos a través de la reflexión.

internal interface IBaseInterface {
    string GetValue();
}

public abstract class MyBase : IBaseInterface {
    string IBaseInterface.GetValue()
    { return "MyBase"; }
}

public class InheritedClass : MyBase {
    public void PrintValue(IBaseInterface someclass)
    { Console.WriteLine(someclass.GetValue()); }
}

Quizás me estoy perdiendo algo, pero deberías poder marcarlo como protected internal y lograr sus objetivos.

namespace Foo
{
    class A
    {
        protected internal void D() { Console.WriteLine(this.ToString() + " says 'Blah'"); }
    }
}

namespace Bar
{
    class B : Foo.A 
    {
        public B()
        {
        }
    }
}

namespace Baz
{
    class C : Foo.A
    {
        public C()
        {
            D();
            Bar.B b = new Bar.B();
            b.D();

            Foo.A a = new Foo.A();
            a.D();
        }
    }
}

Para ver la salida

Baz.C c = new Baz.C();

Todo este es código legal. Foo.a es la base, Bar.B y Baz.c heredan de Foo.A. Void D es un miembro interno protegido de A. Baz.c puede invocar d () como se esperaba, así como crear instancias de Bar.B y Foo.a e invocar también sus métodos D ().

protected internal Los miembros son visibles para todas las clases descendientes en cualquier asamblea y todas las clases dentro de la misma asamblea que la base. La accesibilidad termina fuera de esos límites. Clases no descendientes dentro de las mismas asambleas que los niños no podrían ver al miembro.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top