Можно ли «расширить» свойство «класс»? - PullRequest
4 голосов
/ 11 сентября 2009

Я новичок в C # (начался на прошлой неделе), так что будьте спокойны со мной;). Я хотел бы знать, могу ли я как-то написать собственное свойство, позвольте мне объяснить:

У меня есть несколько частичных классов, которые я добавляю, добавляя свойства, но шаблон всех методов получения и установки одинаков, поэтому я хотел бы разложить это на части:

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

Как видите, единственное, что изменилось, это Ressource1 / Ressource2. Моя цель - написать что-то вроде:

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

    public LocalizedString TravelDescription(Ressource2);
}

У кого-нибудь есть идея сделать это или другая идея сделать мой код чище? Спасибо,

Гийом

Ответы [ 7 ]

7 голосов
/ 11 сентября 2009

Нет возможности сделать это внутри самого C # или .NET, но если вы делаете много из них, возможно, стоит изучить аспектно-ориентированное программирование через postsharp . По сути, это позволит вам определить атрибут, который приведет к добавлению дополнительного кода во время компиляции. Код, который вы вводите, будет примерно таким:

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

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

И во время компиляции PostSharp заменит свойство шаблоном, который вы определили в новом классе LocalizedPropertyAttribute.

3 голосов
/ 11 сентября 2009

Вы не можете сделать это вполне столь же кратким, как то, что вы описываете, но вы можете уменьшить сложность и избыточность сеттеров.

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); }
}
1 голос
/ 11 сентября 2009

Я не знаю точно, чего вы пытаетесь достичь, но вы можете усложнять ситуацию. Разве этого не достаточно?

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

где Resources - это сгенерированный класс (из файла resx) для локализованных ресурсов. У меня такое ощущение, что вы пытаетесь создать собственную структуру локализации, потому что вы еще не знаете, что .NET уже имеет инфраструктуру для этого .

0 голосов
/ 11 сентября 2009

Вы могли бы упростить свою жизнь, инкапсулировав свою логику получения и установки в базовый класс, а затем просто вызывая эти методы из любых создаваемых вами новых свойств (просто действуя как тонкая оболочка для этих методов). Вот пример:

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

}

... Таким образом, в ваших свойствах очень мало логики, и вы повторяете меньше кода. Это предполагает следующие классы (которые я издевался как обобщенные):

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

public class Ressource<T>
{
    public T DefaultValue { get; set; }
}
0 голосов
/ 11 сентября 2009

Вы можете реализовать одно индексированное свойство, предоставляя вам один из следующих двух вариантов синтаксиса на основе ваших предпочтений. Код в основном будет функцией, которая принимает конкретно названный ресурс и возвращает правильное содержимое.

Travel t = new Travel();
string x = t["Name"];
    or 
string x = t[Travel.Name];
0 голосов
/ 11 сентября 2009

Это не имеет смысла. используя свойства, которые у вас есть, вы можете просто написать:

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

Если вы перешли на желаемый способ, вам также потребуется указать параметр

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

все, что вы можете сделать, это создать эмулятор "propertyBag"

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

Вы бы получили доступ к этому так:

   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];    
0 голосов
/ 11 сентября 2009

Нет, такого способа нет. Это было бы возможно в php , но не в C #.

В этом случае вам следует изменить свой подход к свойствам.

UPD: Возможно, вы могли бы использовать что-то подобное для каждого свойства (за исключением его очевидной слабости):

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;
        }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...