C# - 扩展/添加接口到重写方法的参数

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

我对 C# 还很陌生。我正在尝试派生一个类

UIObjectContainer : UIObject
,它重写一个方法
FillProperties
,该方法“填充”参数
Properties
(仅保存杂项数据)。

我想在派生类中扩展此参数以“整理”基类,并允许

Properties
实例仅包含必要的属性,而不是所有可能的属性。

在我当前的使用中,我只是将几个变量隐藏在

Properties
中,然后在派生类中访问它们。每个空属性仍然消耗 4-8 个字节,具体取决于系统,而属性字典需要每个属性 20 个字节,仅具有空属性似乎更适合我的场景。

这是我当前代码的简化:

public class Properties 
{
    public Color basePropertyColor;
    public List<Color> containerPropertyItemColors;
}

public class UIObject 
{
    public virtual void FillProperties(Properties properties) 
    {
        properties.basePropertyColor = Color.grey;
    }
}

public class UIObjectContainer : UIObject 
{
    public override void FillProperties(Properties properties) 
    {
        properties.containerPropertyItemColors = new List<Color>() { Color.red };
        base.FillProperties(properties);
    }
}

此代码的缺点是

Properties
消耗了不必要的内存,并且包含多个参数,这些参数组合在一起,看起来应该是
Properties
之上的接口。

理想情况下,这个接口(或派生类)将在运行时注入到属性中,具体取决于我们所在的类以及它有哪些要求。这里的界面设计模式似乎很有前途,因为它允许您稍后检查

Properties
是否属于某种类型,并使用
is
关键字对属性执行其他逻辑。

我尝试了以下方法,但似乎虽然这不会导致编译错误,但它无法按预期工作。

public class Properties 
{
    public Color basePropertyColor;
}

public class UIObject 
{
    public virtual void FillProperties(Properties properties) 
    {
        properties.basePropertyColor = Color.grey;
    }
}

public class PropertiesContainer : Properties, PropertiesWithMultipleItems 
{
    public float containerPropertyItemColors { get { return new List<Color>() { Color.red } }; }
}

public interface PropertiesWithMultipleItems 
{
    public List<Color> containerPropertyItemColors { get; }
}

public class UIObjectContainer : UIObject 
{
    public override void FillProperties(Properties properties) 
    {
        properties = new PropertiesContainer();
        properties.containerPropertyItemColors = 1;
        base.FillProperties(properties);
    }
}

有人可以看一下所需的实现并让我知道

Properties
需要适应什么设计模式才能在运行时以所需的方式进行扩展?

扩展方法:https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods,很有前途,但似乎受到相同的接口/分组的影响问题。

c# inheritance interface polymorphism code-injection
2个回答
0
投票

在最后的示例代码中,这一行完全消除了传入的内容:

properties = new PropertiesContainer();

您也许应该将最后一堂课更改为:

public class UIObjectContainer : UIObject {
    public override void FillProperties(Properties properties) {
        if (properties is not PropertiesContainer)
        {
            properties = new PropertiesContainer() { basePropertyColor = properties.basePropertyColor };
        }
        var container = properties as PropertiesContainer;
        container.containerPropertyItemColors = 1;
        base.FillProperties(container);
    }
}

这只是一个粗略的例子。但基本上,如果属性不是正确的派生类型,您需要创建新的派生类型对象并克隆/复制原始对象的值。您当前的代码只是删除了传入的原始对象并创建了派生类型的全新空对象。

另一种选择是:

public class UIObjectContainer : UIObject {
    public override void FillProperties(Properties properties) {
        if (properties is not PropertiesContainer)
        {
            throw new InvalidOperationException();
        }
        var container = properties as PropertiesContainer;
        container.containerPropertyItemColors = 1;
        base.FillProperties(container);
    }
}

如果没有获得预期的派生类型,基本上会抛出异常。 InvalidOperationException 只是一个示例异常。您可以创建一个自定义异常来抛出,或者可能有一个更合适的预先存在的异常来抛出,这对您的 api 来说是合乎逻辑的。


0
投票

这感觉像是泛型可以发挥作用的地方;因为您可以将属性类型指定为通用参数:

public class Properties {
    public Color basePropertyColor {get; set;}
}
public class UIObject<TProperties> where TProperties : Properties {
    public virtual void FillProperties(TProperties properties) {
        properties.basePropertyColor = Color.grey;
    }
}

public class PropertiesContainer : Properties {
    public float containerPropertyItemColors {get; set;}
}
public class UIObjectContainer : UIObject<PropertiesContainer> {
    public override void FillProperties(PropertiesContainer properties) {
        properties = new PropertiesContainer();
        properties.containerPropertyItemColors = 1;
        base.FillProperties(properties);
    }
}

就我个人而言,我会更改

FillProperties
以返回
PropertiesContainer
,而不是仅仅为了保持事物的整洁而改变你的类状态。这将允许您将
UIObject
作为模板模式,以强制派生的
FillProperties
方法存在并被调用。

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