2017-02-24 100 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