Pregunta

Soy nuevo en C # (comencé la semana pasada), así que sé genial conmigo;). Me gustaría saber si de alguna manera puedo escribir una propiedad personalizada, déjenme explicar:

Tengo algunas clases parciales que completo agregando propiedades, pero el patrón de todos los captadores y definidores son los mismos, así que me gustaría factorizar esto:

public partial class Travel
{
    public String TravelName
    {
        get
        {
            return LocaleHelper.GetRessource(Ressource1);
        }
        set
        {
            if (this.Ressource1 == null)
                Ressource1 = new Ressource() { DefaultValue = value };
            else
                Ressource1.DefaultValue = value;
        }
    }

    public String TravelDescription
    {
        get
        {
            return LocaleHelper.GetRessource(Ressource2);
        }
        set
        {
            if (this.Ressource2 == null)
                Ressource2 = new Ressource() { DefaultValue = value };
            else
                Ressource2.DefaultValue = value;
        }
    }
}

Como puede ver, lo único que cambia es Ressource1 / Ressource2. Mi objetivo es poder escribir algo como:

public partial class Travel
{
    public LocalizedString TravelName(Ressource1);

    public LocalizedString TravelDescription(Ressource2);
}

¿Alguien tiene una idea para hacer esto, u otra idea para hacer que mi código sea más limpio? Gracias

Guillaume

¿Fue útil?

Solución

No hay ninguna facilidad para hacer esto dentro de C # o .NET, pero si está haciendo muchos de estos, puede valer la pena investigar la programación orientada a aspectos a través de postsharp . Básicamente le permitirá definir un atributo que hace que se inyecte código adicional en tiempo de compilación. El código que escriba será algo así como:

public partial class Travel
{
    [LocalizedProperty(source = "Ressource1")
    public string TravelName { get; set; }

    [LocalizedProperty(source = "Ressource2")
    public string TravelDescription{ get; set; }
}

Y en el momento de la compilación, PostSharp reemplazará la propiedad con una plantilla que haya definido en la nueva clase LocalizedPropertyAttribute.

Otros consejos

No puede hacerlo bastante tan breve como lo que describe, pero puede disminuir la complejidad y la redundancia de los configuradores.

private void SetRessource(ref Ressource res, string value)
{
    if(res == null) res = new Ressource();

    res.DefaultValue = value;
}

public String TravelName
{
    get { return LocaleHelper.GetRessource(Ressource1); }
    set { SetRessource(ref this.Ressource1, value); }
}

public String TravelDescription
{
    get { return LocaleHelper.GetRessource(Ressource2); }
    set { SetRessource(ref this.Ressource2, value); }
}

No sé exactamente lo que estás tratando de lograr, pero puedes estar haciendo las cosas demasiado complicadas. ¿No sería esto suficiente?

public class Travel
{
   /// <summary>
   /// Creates a new instance of <see cref="Travel"/>.
   /// </summary>
   public Travel()
   {
      this.TravelName = Resources.DefaultTravelName;
      this.TravelDescription = Resources.DefaultTravelDescription;
   }

   public string TravelName { get; set; }

   public string TravelDescription { get; set; }
}

donde Resources es una clase generada (desde un archivo resx) para recursos localizados. Tengo la sensación de que está intentando crear su propio marco de localización porque aún no sabe que .NET ya tiene infraestructura para eso .

No, no hay tal manera. Sería posible en php pero no en C #.

Debería cambiar su enfoque de las propiedades en este caso.

UPD: Probablemente podría usar algo como esto para cada propiedad (excepto por su evidente debilidad):

public class Prop
{
    Resource _res;

    public Prop(Resource res)
    {
        this._res = res;
    }

    public string Value
    {
        get
        {
            return LocaleHelper.GetRessource(_res);
        }
        set
        {
            if(_res == null)
                // This is a weak point as it's now
                // as it wont work
            else
                _res.DefaultValue = value;
        }
}

Puede implementar una sola propiedad indexada, que le ofrece una de las siguientes dos opciones de sintaxis según su preferencia. El código básicamente sería una función que acepta el recurso nombrado específicamente y devuelve el contenido correcto.

Travel t = new Travel();
string x = t["Name"];
    or 
string x = t[Travel.Name];

Podría facilitarle la vida encapsulando su lógica getter y setter en una clase base y luego simplemente llamando a esos métodos desde cualquier propiedad nueva que cree (simplemente actuando como una envoltura delgada alrededor de esos métodos). Aquí hay un ejemplo:

public class Travel : LocalizedRessourceSubscriber
{

    private Ressource<string> Ressource1 = null;
    private Ressource<string> Ressource2 = null;

    public String TravelName { 
        get { return GetRessource<string>(Ressource2); }
        set { SetRessource<string>(Ressource1, value); } 
    }

    public String TravelDescription {
        get { return GetRessource<string>(Ressource2); }
        set { SetRessource<string>(Ressource2, value); } 
    }

}

public class LocalizedRessourceSubscriber
{

    protected T GetRessource<T>(Ressource<T> Source)
    {
        return LocaleHelper.GetRessource<T>(Source);
    }

    protected void SetRessource<T>(Ressource<T> Source, T Value)
    {
       (Source ?? 
           (Source = new Ressource<T>())
                ).DefaultValue = Value;
    }

}

... De esta manera, hay muy poca lógica en sus propiedades y está repitiendo menos código. Esto supone las siguientes clases (que me burlé como genérico):

public static class LocaleHelper
{
    public static T GetRessource<T>(Ressource<T> Source)
    {
        return default(T);
    }
}

public class Ressource<T>
{
    public T DefaultValue { get; set; }
}

Eso no tiene sentido. utilizando las propiedades de la forma en que las tiene actualmente, simplemente puede escribir:

   Travel t = new Travel();
   string tvlName = t.TravelName;    
   string desc = t.TravelDescription;

Si cambiaste a la forma que deseas, también deberías especificar el parámetro

   Travel t = new Travel();
   LocalizedString tvlName = t.TravelName([someresopurcedesignator]);    
   LocalizedString desc = t.TravelDescription([someresopurcedesignator]);  

todo lo que puedes hacer es hacer una " propertyBag " emulador

   public class Travel 
   {
       private LocalizedString props = new LocalizedString();
       public LocalizedString Propertys
       {
          get { return props; }
          set { props = value; }
       }

   }

   public class LocalizedString // this is property Bag emulator
   {
       public string this[string resourceName]
       {
           get{ return LocaleHelper.GetRessource(resourceName); }
           set{ LocaleHelper.GetRessource(resourceName) = value; }
       }
   }

Accedería a esto así:

   Travel t = new Travel();
   t.Propertys[NameResource1] = "Bob Smith";
   t.Propertys[DescriptionResource2] = "Fun trip to discover the orient";
   string tvlName = t.Propertys[NameResource1];    
   string desc    = t.Propertys[DescriptionResource2];    
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top