2017-02-24 96 views
1

我有一個外部庫的類對象,我想添加一些附加屬性。使用附加屬性擴展類

假設外部類:

public class ExternalClass 
{ 
    public string EXproperty1 {get;set;} 
    public string EXproperty2 {get;set;} 
    public string EXproperty3 {get;set;} 

    public ExternalClass(){} 
} 

和我有被填充爲

List<ExternalClass> listOfExternalClass=new List<ExternalClass>(); 
listOfExternalClass=GetListOfExternalClass(); 

我可以通過創建一個新的類繼承這個類,這些對象的列表,添加附加屬性並使外部類成爲屬性。

public class NewClass 
{ 
    public ExternalClass ExternalClass {get;set;} 
    public string NewProperty1 {get;set;} 
    public string NewProperty2 {get;set;} 

    public NewClass(){} 
    public NewClass(ExternalClass externalClass){ 
     this.ExternalClass=externalClass; 
    } 
} 

但受外部類的原始列表轉換爲新類的列表,我將不得不創造新類一個新的列表,並通過原始列表創建一個新的對象,並將其添加到迭代列表,像

List<NewClass> listOfNewClass=new List<NewClass>(); 
foreach(var externalClass in listOfExternalClass) 
{ 
    listOfNewClass.Add(new NewClass(externalClass)); 
} 

我會再能訪問諸如

listOfNewClass.FirstOrDefault().ExternalClass.EXproperty1; 

我能做到這一點與繼承或者是有一個更有效的方法外部性?

理想我想通過調用類的屬性直到結束:

listOfNewClass.FirstOrDefault().EXproperty1; 
+4

爲什麼不inheretance?你已經嘗試過了嗎? –

+0

這就是這樣的問題總是會導致多個答案,都是一樣的 – MickyD

+0

您可能想閱讀[Eric Lippert關於monads的博客系列](https://ericlippert.com/2013/02/21/monads-part-one) 。 – OldFart

回答

3

如果你實際上可以擴展外部類很容易實現:

public class NewClass: ExternalClass 
{ 
    public string NewProperty1 {get;set;} 
    public string NewProperty2 {get;set;} 

    public NewClass(){} 
    public NewClass(ExternalClass externalClass){ 
     // you would have to copy all the properties 
     this.EXproperty1 = externalClass.EXproperty1; 
    } 
} 
+0

這就是我開始做的,但有太多的屬性可以映射。如果外部類中的任何屬性發生更改或被添加/刪除,這也將證明是有問題的。 – DeclanMcD

+0

啊哈,也許是完全動態的東西,但這可能證明太複雜:http://stackoverflow.com/questions/3810488/adding-a-property-to-an-existing-class –

+0

或自動複製所有屬性請參閱:http ://stackoverflow.com/questions/930433/apply-properties-values-from-one-object-to-another-of-the-same-type-automaticall –

1

是繼承是你在找什麼:

public class ExternalClass 
{ 
    public string EXproperty1 { get; set; } 
    public string EXproperty2 { get; set; } 
    public string EXproperty3 { get; set; } 

    public ExternalClass() { } 
} 

public class NewClass:ExternalClass 
{    
    public string NewProperty1 { get; set; } 
    public string NewProperty2 { get; set; } 
    public NewClass() { }   
} 
3

這當然可以通過繼承來完成。考慮以下。

//Inherit from our external class 
public class NewClass: ExternalClass 
{ 
    //Note we do not have a copy of an ExternalClass object here. 
    //This class itself will now have all of its instance members. 
    public string NewProperty1 {get;set;} 
    public string NewProperty2 {get;set;} 

    //Base will call the constructor for the inherited class. 
    //If it has parameters include those parameters in NewClass() and add them to base(). 
    //This is important so we don't have to write all the properties ourself. 
    //In some cases it's even impossible to write to those properties making this approach mandatory. 
    public NewClass(): base() 
    { 

    } 
} 

幾件事情需要知道:

  • 你的代碼稱爲包裝。這是因爲它「包裝」了另一班或一組班級。
  • 您不能從標記爲密封的類繼承。
  • 在C#中,類默認情況下是不封裝的。如果他們被封閉,開發人員會故意阻止你繼續從課程中繼承。這通常是有原因的。
1

如果您希望(或需要)代表團,而不是一個副本,你可以這樣做:

public class NewClass 
{ 
    public ExternalClass ExternalClass {get;set;} 
    public string NewProperty1 {get;set;} 
    public string NewProperty2 {get;set;} 

    public string EXproperty1 {get { return this.ExternalClass.EXproperty1; };set{ this.ExternalClass.EXproperty1 = value; }; } 
    public string EXproperty2 {get { return this.ExternalClass.EXproperty2; };set{ this.ExternalClass.EXproperty2 = value; }; } 
    public string EXproperty3 {get { return this.ExternalClass.EXproperty3; };set{ this.ExternalClass.EXproperty3 = value; }; } 

    public NewClass(){} 
    public NewClass(ExternalClass externalClass){ 
     this.ExternalClass=externalClass; 
    } 
} 
+0

+1這就是我忙於打字和讚美@ Licht的答案,通過填寫課程封閉時可以做什麼。唯一的缺點是缺乏多態性。 –

0

,而不是針對特定類型,對接口的工作工作。

下面我顯示爲「變換」外部數據到定義良好的接口(IDocument)的facade patternadapter pattern混合,有效抽象的東西你正在努力。

例1:約界面查詢

這裏是你的工作對類型:

public interface IDocument { 
    string Name { get; set; } 
} 

public interface IMetadata { 
    string[] Tags { get; set; } 
} 

這是你自己的表現,如果你需要任何:

public class RichDocument : IDocument, IMetadata { 
    public string Name { get; set; } 
    public string[] Tags { get; set; } 
} 

這是對外部數據的包裝:

(正面和/或適配器的雜種混合概念)

public class ExternalClass { 
    public string Whatever { get; set; } 
} 

public class ExternalDocument : IDocument /* only a basic object */ { 
    private readonly ExternalClass _class; 

    public ExternalDocument(ExternalClass @class) { 
     _class = @class; 
    } 

    public string Name { 
     get { return _class.Whatever; } 
     set { _class.Whatever = value; } 
    } 
} 

以及如何使用所有演示:

internal class Demo1 { 
    public Demo1() { 
     var documents = new List<IDocument> { 
      new ExternalDocument(new ExternalClass()), 
      new RichDocument() 
     }; 

     foreach (var document in documents){ 
      var name = document.Name; 
      Console.WriteLine(name); 

      // see if it implements some interface and do something with it 
      var metadata = document as IMetadata; 
      if (metadata != null) { 
       Console.WriteLine(metadata.Tags); 
      } 
     } 
    } 
} 

實施例2:關於組件

查詢

通過推動概念以統一的方式處理所有事情,你可以在.NET框架,遊戲開發或其他任何東西中找到它......

你會工作對

定義:

public interface IContainer { 
    IList<IComponent> Components { get; } 
} 

public interface IComponent { 
    // it can be/do anything 
} 

一些組件你查詢一下:

public interface IDocument : IComponent { 
    string Name { get; set; } 
} 

public interface IMetadata : IComponent { 
    string[] Tags { get; set; } 
} 

你的 '內部' 類型:

public class Container : IContainer { 
    public Container() { 
     Components = new List<IComponent>(); 
    } 

    public IList<IComponent> Components { get; } 
} 

你 '包裝' 免受外部數據:

public class ExternalClass { 
    public string Whatever { get; set; } 
} 

public class ExternalContainer : IContainer { 
    private readonly List<IComponent> _components; 

    public ExternalContainer(ExternalClass @class) { 
     _components = new List<IComponent> {new ExternalDocument(@class)}; 
    } 

    public IList<IComponent> Components { 
     get { return _components; } 
    } 
} 

public class ExternalDocument : IDocument { 
    private readonly ExternalClass _class; 

    public ExternalDocument(ExternalClass @class) { 
     _class = @class; 
    } 

    public string Name { 
     get { return _class.Whatever; } 
     set { _class.Whatever = value; } 
    } 
} 

以及使用例如:

public class Demo2 { 
    public Demo2() { 
     var containers = new List<IContainer> { 
      new ExternalContainer(new ExternalClass()), 
      new Container() 
     }; 

     foreach (var container in containers) { 
      // query container for some components 

      var components = container.Components; 

      var document = components.OfType<IDocument>().FirstOrDefault(); 
      if (document != null) { 
       Console.WriteLine(document.Name); 
      } 

      var metadata = components.OfType<IMetadata>().FirstOrDefault(); 
      if (metadata != null) { 
       Console.WriteLine(metadata.Tags); 
      } 
     } 
    } 
} 

注意

與繼承的問題是,它是一個非常嚴格的辦法,通常一旦你開始這樣做,並在某些時候,你碰了壁,並希望要恢復,很難擺脫它。

通過解決抽象問題,事情更加靈活,事物解耦。

這裏有兩個例子,可能煽動你改變你的做法:

Composition over inheritance

Using Components

+0

你是對的,組合(或委託)在很多情況下都是可行的,但是你的類型層次結構爲一個簡單的問題帶來了巨大的複雜性。總是KISS(https://en.wikipedia.org/wiki/KISS_principle),直到你確實需要使用不同類型的對象。 –

+0

你是100%的權利。我告訴人們的東西,但大部分時間都忘了自己做 – Aybe