Domanda

Sono nuovo in C # (iniziato la scorsa settimana), quindi sii gentile con me;). Vorrei sapere se posso in qualche modo scrivere una proprietà personalizzata, mi spiego:

Ho alcune classi parziali che ho completato aggiungendo proprietà, ma lo schema di tutti i getter e setter è lo stesso, quindi vorrei fattorizzare questo:

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

Come puoi vedere, l'unica cosa che cambia è Ressource1 / Ressource2. Il mio obiettivo è riuscire a scrivere qualcosa del tipo:

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

    public LocalizedString TravelDescription(Ressource2);
}

Qualcuno ha un'idea per rendere questo, o un'altra idea per rendere il mio codice più pulito? Grazie

Guillaume

È stato utile?

Soluzione

Non è possibile farlo all'interno di C # o .NET stesso, ma se si stanno facendo molti di questi potrebbe valere la pena studiare la programmazione orientata all'aspetto attraverso postsharp . Fondamentalmente ti permetterà di definire un attributo che causa l'iniezione di codice extra in fase di compilazione. Il codice digitato è simile a:

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

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

E in fase di compilazione PostSharp sostituirà la proprietà con un modello che hai definito nella nuova classe LocalizedPropertyAttribute.

Altri suggerimenti

Non puoi renderlo abbastanza succinto come quello che descrivi, ma puoi ridurre la complessità e la ridondanza dei setter.

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

Non so esattamente cosa stai cercando di ottenere, ma potresti rendere le cose troppo complicate. Non sarebbe sufficiente?

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

dove Resources è una classe generata (da un file resx) per risorse localizzate. Ho la sensazione che stai cercando di creare il tuo framework di localizzazione perché non sai ancora che .NET dispone già di un'infrastruttura per questo .

No, non esiste. Sarebbe possibile in php ma non in C #.

In questo caso dovresti cambiare il tuo approccio lontano dalle proprietà.

UPD: Probabilmente potresti usare qualcosa del genere per ogni proprietà (tranne che per la sua ovvia debolezza):

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

Potresti implementare una singola proprietà indicizzata, dandoti una delle due seguenti opzioni di sintassi in base alle tue preferenze. Il codice sarebbe sostanzialmente una funzione che accetta la risorsa specificata e restituisce il contenuto giusto.

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

Potresti semplificarti la vita incapsulando la tua logica getter e setter in una classe base e quindi semplicemente chiamando quei metodi da qualsiasi nuova proprietà che crei (agendo semplicemente come thin wrapper attorno a quei metodi). Ecco un esempio:

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

}

... In questo modo, c'è poca logica nelle tue proprietà e stai ripetendo meno codice. Questo presuppone le seguenti classi (che ho deriso come generico):

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

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

Non ha senso. usando le proprietà come le hai attualmente, puoi semplicemente scrivere:

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

Se si è modificato nel modo desiderato, è necessario specificare anche il parametro

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

tutto quello che puoi fare è creare un " propertyBag " emulatore

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

Avresti accesso a questo in questo modo:

   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];    
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top