Question

I'm new to C# (started last week) so be cool with me ;). I'd like to know if I can somehow write a custom property, let me explain:

I have some partial classes that I complete by adding properties, but the pattern of all the getters and setters are the same so I'd like to factorize this:

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

As you can see, the only thing that change is Ressource1/Ressource2. My goal is be able to write something like:

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

    public LocalizedString TravelDescription(Ressource2);
}

Anybody have an idea to make this, or another idea to make my code cleaner? Thank you,

Guillaume

Was it helpful?

Solution

There is no facility to do this inside C# or .NET itself, but if you are doing lots of these it may be worth investigating aspect orientated programming through postsharp. Basically it will allow you to define an attribute that causes extra code to be injected at compile time. The code you type be something like:

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

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

And at compile time PostSharp will replace the property with a template you have defined in the new LocalizedPropertyAttribute class.

OTHER TIPS

You can't make it quite as succinct as what you describe, but you can decrease the complexity and redundancy of the setters.

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

I don't know exactly what you are trying to achieve, but you may be making things too complicated. Wouldn't this be sufficient?

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

where Resources is a generated class (from a resx file) for localized resources. I have a feeling you are trying to build your own localization framework because you don't know yet that .NET already has infrastructure for that.

No, there is no such way. It would be possible in php but not in C#.

You should change your approach away from properties in this case.

UPD: Probably you could use something like this for every property (except for it's obvious weakness):

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

You could implement a single indexed property, giving you one of the following two syntax choices based on your preference. The code would basically be a function that accepts the specifically named resource and returns the right content.

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

You could make your life easier by encapsulating your getter and setter logic in a base class and then simply calling those methods from any new properties you create (simply acting as thin wrapper around those methods). Here's an example:

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

}

...This way, there is very little logic in your properties and you are repeating less code. This assumes the following classes (which I mocked as genericized):

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

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

That doesn't make sense. using propertys the way you currently have them, you can simply write:

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

If you changed to the way you want you'd have to specify the parameter as well

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

all you could do is make a "propertyBag" emulator

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

You would access this like this:

   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];    
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top