2008-10-15 35 views
145

Duplicar posible:
Why does C# not provide the C++ style ‘friend’ keyword?¿Cuál es el equivalente de C# de un amigo?

me gustaría las variables miembro privadas de una clase para ser accesible a una clase probador sin exponerlos a otras clases.

En C++ solo declararía la clase Tester como amigo, ¿cómo hago esto en C#? ¿Puede alguien darme un ejemplo?

+2

No debe probar miembros privados directamente como si fueran accesibles como públicos. Por lo general, las personas solo realizan pruebas contra miembros públicos: http://stackoverflow.com/a/5662371/62921 Los miembros privados se probarán en el camino indirectamente. – ForceMagic

Respuesta

213

No hay un equivalente directo de "amigo": lo más cercano que está disponible (y no está muy cerca) es InternalsVisibleTo. Solo he usado este atributo para probar, ¡donde es muy útil!

Ejemplo: para ser colocado en AssemblyInfo.cs

[assembly: InternalsVisibleTo("OtherAssembly")] 
+20

+1 por enseñarme algo nuevo. – Brian

+7

Nota interesante, en VB.NET 'Internal' todavía se llama' Amigo'. – Jeff

+1

MSDN dice: "Todos los tipos no públicos en un ensamblaje son visibles para otro ensamblaje" ¡Qué feo! ¿Quién va a usar esa tontería? Prefiero la respuesta de RobG. – Elmue

13

No hay una palabra clave 'amigo' en C#, pero una opción para probar los métodos privados es utilizar System.Reflection para obtener un identificador para el método. Esto le permitirá invocar métodos privados.

dado una clase con esta definición:

public class Class1 
{ 
    private int CallMe() 
    { 
     return 1; 
    } 
} 

se puede invocar utilizando este código:

Class1 c = new Class1(); 
Type class1Type = c.GetType(); 
MethodInfo callMeMethod = class1Type.GetMethod("CallMe", BindingFlags.Instance | BindingFlags.NonPublic); 

int result = (int)callMeMethod.Invoke(c, null); 

Console.WriteLine(result); 

Si está utilizando Visual Studio Team System, entonces puede obtener VS para generar automáticamente una clase proxy con accesadores privados en él haciendo clic con el botón derecho en el método y seleccionando "Crear pruebas unitarias ..."

+0

La reflexión tiene un alto costo de rendimiento y a menudo conduce a un código poco legible. El enfoque de "clase externa parcial" es mucho mejor para mí cuando es una opción. – AFract

35

Tome un patrón muy común. Class Factory hace Widgets. La clase de fábrica necesita rebuscar con las partes internas, porque es la fábrica. Ambos se implementan en el mismo archivo y son, por diseño, deseo y naturaleza, clases estrechamente conectadas; de hecho, Widget es realmente solo un tipo de salida de fábrica.

En C++, haga de Factory un amigo de la clase de Widget.

En C#, ¿qué podemos hacer? La única solución decente que se me ha ocurrido es inventar una interfaz, IWidget, que solo expone los métodos públicos, y tiene las interfaces de devolución de fábrica de IWidget.

Esto implica una buena dosis de tedio, exponiendo de nuevo todas las propiedades públicas de forma natural en la interfaz.

52

El equivalente de armario es crear una clase anidada que podrá acceder a los miembros privados de la clase externa. Algo como esto:

class Outer 
{ 
    class Inner 
    { 
     // This class can access Outer's private members 
    } 
} 

o si lo prefiere poner la clase interna en otro archivo:

Outer.cs 
partial class Outer 
{ 
} 


Inner.cs 
partial class Outer 
{ 
    class Inner 
    { 
     // This class can access Outer's private members 
    } 
} 
+6

Tenga en cuenta que para acceder a los miembros de la clase externa, a menos que la variable sea estática (o const), aún necesita una referencia a la instancia de Outer. Según la respuesta aceptada aquí: http://stackoverflow.com/questions/3155172/inner-class-and-outer-class-in-c-sharp – Itison

+0

Me pregunto si podría usar métodos de extensión para la clase 'Inner'. ¡Voy a probarlo! :) – Jess

+2

¡Doh! Los métodos de extensión no están permitidos en una clase interna. – Jess

6

se puede simular un acceso amigo si la clase que se le da el derecho de acceso está dentro de otro y si los métodos que está exponiendo están marcados como internos o internos. Debe modificar el conjunto que desea compartir y agregar las siguientes configuraciones a AssemblyInfo.cs:

// Expose the internal members to the types in the My.Tester assembly 
[assembly: InternalsVisibleTo("My.Tester, PublicKey=" + 
"012700000480000094000000060200000024000052534131000400000100010091ab9" + 
"ba23e07d4fb7404041ec4d81193cfa9d661e0e24bd2c03182e0e7fc75b265a092a3f8" + 
"52c672895e55b95611684ea090e787497b0d11b902b1eccd9bc9ea3c9a56740ecda8e" + 
"961c93c3960136eefcdf106955a4eb8fff2a97f66049cd0228854b24709c0c945b499" + 
"413d29a2801a39d4c4c30bab653ebc8bf604f5840c88")] 

La clave pública es opcional, según sus necesidades.

Cuestiones relacionadas