2009-09-11 172 views
4

我是C#的新手(開始於上週),所以對我很酷;)。 我想知道如果我可以以某種方式寫一個自定義屬性,讓我解釋一下:是否可以「擴展」財產「類」?

我有一些部分類,我通過添加屬性來完成,但所有getters和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); 
} 

任何人有一個想法,使這個或其他想法,使我的代碼更清潔? 謝謝

紀堯姆

+0

您是否知道System.Globalization命名空間/概念? – 2009-09-11 13:47:26

+0

是但我對使用一個數據庫來存儲數據的ressource在網絡上找到很「混亂」(頭痛)... – Guillaume86 2009-09-11 14:32:01

回答

7

沒有工廠做,這裏面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類中定義的模板的屬性。

+0

感謝您的答覆,我想試試;) – Guillaume86 2009-09-11 13:52:05

0

沒有,有沒有這樣的方法。這將是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; 
     } 
} 
-1

這沒有意義。 使用propertys您目前有他們的方式,你可以簡單的寫:

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

上再看一看二傳手LocalizedString的索引器... – 2009-09-11 13:52:51

+0

我認爲你誤解了OP的意圖。他的語法並不意味着對財產的調用變成參數化的;他只是想實現參數化。 – 2009-09-11 13:53:13

+0

@Jeff,那麼也許我還是誤會......如果實現參數化,如何參數值去執行,如果呼叫不被參數化? – 2009-09-11 13:55:13

3

您不能使它相當於儘可能簡潔,但可以降低設置者的複雜性和冗餘度。

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

好主意。一個額外的建議是使得get,set和Ressource成員成爲接口的一部分,如INameProvider。 – mjv 2009-09-11 13:56:05

0

您可以實現單個索引屬性,根據您的偏好給出以下兩種語法選項之一。代碼基本上是一個接受具體命名資源並返回正確內容的函數。

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

我不知道你想達到什麼,但你可能會讓事情變得太複雜。這不就夠了嗎?

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

+0

其實Ressources是LINQ到SQL實體 「EN」, 「FR」, 「ES」 等字符串字段。我的LocaleHelper.GetRessource(資源)返回正確的語言。 (我需要在數據庫中存儲資源,我試圖使用默認的全球化系統,它使用db來代替resx ...)。 我的自定義屬性讓我能夠製作出漂亮的LINQ請求和數據綁定。 – Guillaume86 2009-09-11 14:09:22

+0

BTW您的解決方案是完美的GET部分,但unfortunaly設定的部分是有點複雜... – Guillaume86 2009-09-11 14:19:52

0

你可以讓你的生活你的封裝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; } 
}