views:

527

answers:

7

Hello,

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

A: 

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;
        }
}
zzandy
+6  A: 

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.

Martin Harris
Thank you for your response, I'll try that ;)
Guillaume86
A: 

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];
Charles Bretana
Take another look at the setter on the indexer of LocalizedString...
Adam Robinson
I think you have misunderstood the OPs intent. His syntax is not suggesting that the calls to the property become parameterized; he merely wants the implementation to be parameterized.
Jeff Yates
@Jeff, Then perhaps I still misunderstand... If the implementation is parameterized, how can the parameter value get to the implementation if the calls are not parameterized?
Charles Bretana
@Adam, take a look at the settter where? In my code sample?
Charles Bretana
+2  A: 

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); }
}
Adam Robinson
Good idea. An extra suggestion is to make the get, set and the Ressource member part of an interface, say INameProvider.
mjv
A: 

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];
John Fisher
+1  A: 

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.

Wim Coenen
Actually Ressources are Linq to SQL entities with "en", "fr", "es" etc String fields. My LocaleHelper.GetRessource(Ressource) returns the right language.(I need to have the ressources in a database and i tried to use the default globalization system, it's hell to use a db in place of resx...).My custom properties are there to make me able to make nice LINQ requests and databindings.
Guillaume86
btw your solution is perfect for the get part, but unfortunaly the set part is a little more complex...
Guillaume86
A: 

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