Вопрос

Я новичок в 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);
}

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

Гийом

Это было полезно?

Решение

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

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

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

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

Другие советы

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

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

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

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 для этого уже есть инфраструктура.

Нет, такого способа не существует.Это было бы возможно в 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;
        }
}

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

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

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

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

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

   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];    
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top