2012-06-22 14 views
32

¿Es posible obtener valor sin crear una instancia?C# ¿Obtiene el valor de la propiedad sin crear una instancia?

que tienen esta clase:

public class MyClass 
{ 
    public string Name{ get{ return "David"; } } 

    public MyClass() 
    { 
    } 
} 

Ahora necesito obtener el valor "David", sin crear instancia de MyClass.

+0

Es necesario hacer que la estática – jglouie

+0

hacer que la propiedad Nombre como estática – HatSoft

+17

yo realmente curiosidad por saber lo que el supuesto caso de uso es aquí que hace el PO creo que deberían hacerlo. – Tim

Respuesta

62

Usted puede hacer que la propiedad estática

public static string Name{ get{ return "David"; } } 

Uso:

MyClass.Name; 
+16

+1 porque creo que esta respuesta es más útil para el OP que el ejercicio inútil que actualmente puntúa más alto. –

+7

@michielvoo: Bueno, podría argumentar que el inicio de mi respuesta da * dos * opciones, ya sea que la propiedad sea estática, * o * cree una instancia. Esta respuesta solo da una :) Pero sí, no di ejemplos de * cómo * para hacer la propiedad estática, ya que otras respuestas ya habían cubierto ese terreno. También creo que es útil dar respuestas que brinden información a personas * otras * además del OP. –

+0

Ah, esta es la respuesta obligatoria. Si yo fuera el OP, entonces debo hacerlo. – avirk

1

crear una propiedad estática:

public class MyClass 
{ 
    public static string Name { get { return "David"; } } 

    public MyClass() 
    { 
    } 
} 

Conseguir este modo:

string name1 = MyClass.Name; 
0

Crea una clase estática o una propiedad estática, y no tienes que crear una instancia explícita.

0

Eso no es posible. Como Name es una propiedad de instancia, solo puede obtener su valor si tiene una instancia.

Además, tenga en cuenta que no estamos hablando de un parámetro, sino de una propiedad .

4

Puede hacer su propiedad static, como lo señalan muchos otros.

public static string Name{ get{ return "David"; } } 

Tenga en cuenta que esto significa que las instancias de MyClass ya no tendrá su propia propiedad Name, ya que los miembros estáticos pertenecen a la clase, no las instancias de los objetos individuales de ella.

Editar: En una nota, se mencionó que desea anular la propiedad Name en las subclases. Al mismo tiempo, desea poder acceder a él en el nivel de clase (acceda a él sin crear una instancia de su clase).

Para las propiedades estáticas, simplemente crearía una nueva propiedad Name en cada clase. Ya que son static, siempre (casi siempre, yay reflection) vas a acceder a ellos usando una clase específica, por lo que deberías especificar qué versión de Name quieres obtener. Si quieres probar y hackear el polimorfismo y obtener el nombre de cualquier subclase dada de MyClass, puedes hacerlo usando la reflexión, pero no recomendaría hacerlo.

Usando el ejemplo de su comentario:

public class Dad 
{ 
    public static string Name { get { return "George"; } 
} 

public class Son : Dad 
{ 
    public static string Name { get{ return "Frank"; } 
} 

public static void Test() 
{ 
    Console.WriteLine(Dad.Name); // prints "George" 
    Console.WriteLine(Son.Name); // prints "Frank" 
    Dad actuallyASon = new Son(); 
    PropertyInfo nameProp = actuallyASon.GetType().GetProperty("Name"); 
    Console.WriteLine(nameProp.GetValue(actuallyASon, null)); // prints "Frank" 
} 

Como nota al margen, ya que está declarando una propiedad que tiene solamente un captador y devuelve un valor constante, recomiendo posiblemente utilizando un const o variable estática readonly en su lugar.

public const string Name = "David"; 
public static readonly string Name = "David"; 

Uso tanto sería el mismo:

string name = MyClass.Name; 

El beneficio principal (y devolución) de const es que todas las referencias a que en realidad están reemplazados por su valor cuando se compila el código. Eso significa que será un poco más rápido, pero si alguna vez cambia su valor, tendrá que volver a compilar TODO el código que lo haga referencia.

+0

Gracias a todos por la respuesta. Pero necesito anular las propiedades del nombre: clase pública Dad { \t cadena virtual pública Nombre {get {return "George"; }} \t papá pública() { \t \t}} clase pública Hijo: Papá { \t cadena public override Nombre {get {return "Frank"; }} \t Hijo pública(): base() { \t \t}} puede ser estática anulado? – user1475694

+0

Las propiedades estáticas no pueden ser virtuales, pero no es necesario que las tenga, ya que las está accediendo a nivel de clase, lo que significa que siempre especifica la clase 'Nombre de la propiedad a la que desea acceder. –

+0

Ok, usaré estática, gracias a todos por su ayuda. – user1475694

91

Respuesta real: no. Es una propiedad de instancia, por lo que solo puede invocarla en una instancia. Debe crear una instancia o hacer que la propiedad sea estática como se muestra en otras respuestas.

Consulte MSDN para obtener más información acerca de la diferencia entre los miembros estáticos y de instancia.

la lengua en la mejilla, pero aún respuesta correcta:

¿Es posible obtener el valor sin crear una instancia?

Sí, pero sólo a través de un código realmente horrible lo que crea cierta IL que pasa en null como this (que no se utiliza en su propiedad), utilizando un DynamicMethod. Código de muestra:

// Jon Skeet explicitly disclaims any association with this horrible code. 
// THIS CODE IS FOR FUN ONLY. USING IT WILL INCUR WAILING AND GNASHING OF TEETH. 
using System; 
using System.Reflection.Emit; 

public class MyClass 
{ 
    public string Name { get{ return "David"; } } 
} 


class Test  
{ 
    static void Main() 
    { 
     var method = typeof(MyClass).GetProperty("Name").GetGetMethod(); 
     var dynamicMethod = new DynamicMethod("Ugly", typeof(string), 
               Type.EmptyTypes); 
     var generator = dynamicMethod.GetILGenerator(); 
     generator.Emit(OpCodes.Ldnull); 
     generator.Emit(OpCodes.Call, method); 
     generator.Emit(OpCodes.Ret); 
     var ugly = (Func<string>) dynamicMethod.CreateDelegate(
         typeof(Func<string>)); 
     Console.WriteLine(ugly()); 
    } 
} 

No haga esto. Ever. Es espantoso. Se debe pisotear, cortar en pedacitos, prender fuego y luego cortar de nuevo. Diversión, ¿no? ;)

Esto funciona porque está usando call en lugar de callvirt. Normalmente el compilador de C# usaría una llamada callvirt, incluso si no está llamando a un miembro virtual porque obtiene la comprobación de referencia nula "gratis" (en lo que respecta a la secuencia IL). Una llamada no virtual como esta no comprueba primero la nulidad de, solo invoca al miembro. Si marcó this dentro de la llamada de propiedad, encontrará que es nulo.

EDIT: Como se ha señalado por Chris Sinclair, que puede hacer que sea más simple uso de una instancia abierta delegado:

var method = typeof(MyClass).GetProperty("Name").GetGetMethod(); 
var openDelegate = (Func<MyClass, string>) Delegate.CreateDelegate 
    (typeof(Func<MyClass, string>), method); 
Console.WriteLine(openDelegate(null)); 

(! Pero, de nuevo, por favor no)

+0

@ R.MartinhoFernandes: Absolutamente :) Para ser sincero, ha pasado un tiempo desde que escribí un código malvado. Agregaré más descargos de responsabilidad, etc. al código. –

+0

Aunque estoy muy impresionado, casi quiero rechazar esta respuesta por si alguien lee casi todo, ¡excepto la parte "no lo hagas"! –

+7

@JonSkeet ¿podría usar la técnica que se indica aquí para evitar la generación IL? http://stackoverflow.com/questions/951624/how-to-create-a-delegate-to-an-instance-method-with-a-null-target EDIT: hmm, tal vez no. Eso es por métodos, no propiedades. –

3

Usted requisitos sí parece extraño , pero creo que estás buscando algún tipo de metadata. Se puede utilizar un atributo para lograrlo:

public class NameAttribute : Attribute { 
    public string Name { get; private set; } 
    public NameAttribute(string name) { 
    Name = name; 
    } 
} 

[Name("George")] 
public class Dad { 
    public string Name { 
    get { 
     return NameGetter.For(this.GetType()); 
    } 
    } 
} 

[Name("Frank")] 
public class Son : Dad { 
} 

public static class NameGetter { 
    public static string For<T>() { 
    return For(typeof(T)); 
    } 
    public static string For(Type type) { 
    // add error checking ... 
    return ((NameAttribute)type.GetCustomAttributes(typeof(NameAttribute), false)[0]).Name; 
    } 
} 

Ahora bien, este código puede obtener los nombres con y sin instancias:

Console.WriteLine(new Dad().Name); 
Console.WriteLine(new Son().Name); 
Console.WriteLine(NameGetter.For<Dad>()); 
Console.WriteLine(NameGetter.For<Son>()); 
2

Cada vez que se escribe código C#, siempre verifique si su método y propiedad de captador/definidor el código hace cualquier cosa en absoluto con otros miembros de instancia de la clase. Si no lo hacen, asegúrese de aplicar la palabra clave estática .Ciertamente el caso aquí, resuelve trivialmente su problema.

La razón por la que realmente publico esta pregunta es porque hay un poco de sesgo de idioma en el trabajo en algunas de las respuestas. La regla C# de que no se puede llamar a un método de instancia en un objeto nulo es una regla de lenguaje C# específica. Es sin duda una muy acertada, realmente ayuda a solucionar NullReferenceExceptions, se generan en el sitio de llamadas en lugar de en algún lugar dentro de un método donde es muy difícil diagnosticar que esta referencia es nula.

Pero esto ciertamente no es un requisito para el CLR, ni de todos los idiomas que se ejecutan en el CLR. De hecho, incluso C# no hace cumplir de manera consistente, se puede pasar por alto fácilmente en un método de extensión:

public static class Extensions { 
    public static bool IsNullOrEmpty(this string obj) { 
     return obj != null && obj.Length > 0; 
    } 
} 
... 
     string s = null; 
     bool empty = s.IsNullOrEmpty(); // Fine 

Y el uso de su propiedad de un lenguaje que no tiene la misma regla funciona bien también. Al igual que C++/CLI:

#include "stdafx.h" 

using namespace System; 
using namespace ClassLibrary1; // Add reference 

int main(array<System::String ^> ^args) 
{ 
    MyClass^ obj = nullptr; 
    String^ name = obj->Name;  // Fine 
    Console::WriteLine(name); 
    return 0; 
} 
Cuestiones relacionadas