代码之家  ›  专栏  ›  技术社区  ›  Guillaume86

是否可以“扩展”属性“类”?

  •  4
  • Guillaume86  · 技术社区  · 15 年前

    我是新来的C(上周开始),所以冷静点。 我想知道我是否可以写一个自定义属性,让我解释一下:

    我有一些通过添加属性完成的分部类,但是所有getter和setter的模式都是相同的,所以我想将其分解为:

    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 回复  |  直到 15 年前
        1
  •  7
  •   Martin Harris    15 年前

    在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类中定义的模板替换该属性。

        2
  •  3
  •   Adam Robinson    15 年前

    你做不到 相当地 正如您所描述的那样简洁,但是您可以减少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); }
    }
    
        3
  •  1
  •   Wim Coenen    15 年前

    我不知道你到底想实现什么,但你可能把事情搞得太复杂了。这还不够吗?

    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 already has infrastructure for that .

        4
  •  0
  •   zzandy    15 年前

    不,没有这样的方法。它将会是 possible in 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;
            }
    }
    
        5
  •  0
  •   John Fisher    15 年前

    您可以实现一个索引属性,根据您的偏好为您提供以下两种语法选择之一。代码基本上是一个接受特定命名资源并返回正确内容的函数。

    Travel t = new Travel();
    string x = t["Name"];
        or 
    string x = t[Travel.Name];
    
        6
  •  0
  •   Robert Venables    15 年前

    通过将getter和setter逻辑封装在基类中,然后从创建的任何新属性中简单地调用这些方法(简单地充当这些方法的瘦包装器),可以使您的生活更轻松。下面是一个例子:

    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; }
    }
    
        7
  •  -1
  •   Charles Bretana    15 年前

    这没有道理。 以您当前拥有的方式使用属性,您只需编写:

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

    你所能做的就是做一个“属性包”模拟器

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