具有附加属性的扩展类

问题描述 投票:2回答:5

我有一个外部库中的类对象,我想向其中添加一些其他属性。

假设外部类是:

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;
c# inheritance
5个回答
4
投票

如果您实际上可以扩展将很容易实现的External类:

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

5
投票

这当然可以通过继承来完成。考虑以下内容。

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

    //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()
    {

    }
}

几件事要知道:

  • 您的代码称为包装器。这是因为它“包装”了另一个或一组类。
  • 您不能从标记为密封的类继承。
  • 在C#中,默认情况下不密封类。如果密封,开发人员将有意阻止您从类继承。这通常是有充分理由的。

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() { }          
}

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
投票

代替使用特定类型,而是使用接口。

[下面,我展示facade patternadapter pattern的混合,以将外部数据“转换”为定义明确的接口(IDocument),有效地抽象您正在处理的事情。

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

Notes

继承的问题是,这是一个非常严格的方法,通常,一旦您开始做它,并且在某个时候碰壁并想还原,就很难摆脱它。

通过反对抽象,事情变得更加灵活,事物之间解耦了。

以下是两个可能促使您改变方法的示例:

Composition over inheritance

Using Components

© www.soinside.com 2019 - 2024. All rights reserved.