我正在用C#编写一个支持插件的应用程序。每个插件都必须自我介绍,以便应用程序可以为其准备适当的环境。当前信息对象看起来更像这样:

class FilterInfo
{
    public InputInfo[] inputs;
    public OutputInfo[] outputs;
    bool IsConfigurable;
    bool IsPlayable;
    string TypeName;
}


这种结构肯定会在将来扩展(但是,我想这不会太大,它的大小可能会增加一倍)。我目前正在考虑如何正确实现此类信息类。

在C ++中,我将通过以下方式进行操作(我将类剥离到一个字段中,以使示例更具可读性):

class FilterInfo
{
private:
    std::vector<const InputInfo> inputs;

public:
    std::vector<const InputInfo> & GetInputs()
    {
        return inputs;
    }

    const std::vector<const InputInfo> & GetInputs() const
    {
        return inputs;
    }
}


现在,该插件将实例化一个FilterInfo类,填写其字段,然后根据请求返回const FilterInfo,从而使任何人都无法更改信息内容(当然,没有人可以)。

在C#中,我只能想象以下“安全”解决方案:

public interface IInputInfo
{
    bool SomeData
    {
        get;
    }
}

public class InputInfo : IInputInfo
{
    private bool someData;

    public bool SomeData
    {
        get
        {
            return someData;
        }
        set
        {
            someData = value;
        }
    }

    public bool IInputInfo.SomeData
    {
        get
        {
            return someData;
        }
    }
}

public interface IFilterInfo
{
    ReadOnlyCollection<IInputInfo> Inputs
    {
        get;
    }
}

public class FilterInfo : IFilterInfo
{
    private InputInfo[] inputs;

    public InputInfo[] Inputs
    {
        get
        {
            return inputs;
        }
        set
        {
            inputs = value;
        }
    }

    public ReadOnlyCollection<IInputInfo> IFilterInfo.Inputs
    {
        return inputs;
    }
}


当然,该插件将返回IFilterInfo而不是FilterInfo,这样数据是只读的(好,我知道反射,问题是通知用户,不应更改数据)。但是,这种解决方案在我看来非常笨拙-尤其是与我之前引用的紧凑版本相比。

另一个解决方案可能是仅使用getter创建FilterInfo,但这将需要以某种方式将数据传递到其中,并且最终可能会导致带有大量参数的庞大构造函数。



编辑:另一个解决方案是创建一个结构,并在每个请求期间返回其副本。但是,数组是通过引用复制的,因此我每次都必须手动复制它们。

另一个是每次有人请求时从头开始构造FilterInfo。

public FilterInfo Info
{
    get
    {
        return new FilterInfo()
            {
                IsConfigurable = true,
                IsPlayable = false,
                Inputs = new[]
                    {
                        new InputInfo()
                            {
                            // (...)
                            }
                    }
            }
    }
}


有解决这个问题的优雅方法吗?

最佳答案

我认为您第一次就知道了:


在可插拔程序集中定义仅允许读取的公共IFilterInfo接口。
在其属性具有内部设置器的插件程序集中的FilterInfo类中实现接口。
有一个方法应要求返回一个新的FilterInfo类实例。惯例建议在每次构造一个新实例的情况下使用一种方法而不是一种属性。 (如果您坚持使用属性,则可以在实例构建后存储该实例,并通过该属性将其返回)


例:

在可插组合件中:

public interface IFilterInfo {
  bool IsPlayable { get; }
  bool IsConfigurable { get; }
}


在插件程序集中:

internal class FilterInfo : IFilterInfo {
  public bool IsPlayable { get; internal set; }
  public bool IsConfigurable { get; internal set; }
}

public IFilterInfo GetFilterInfo() {
  return new FilterInfo() { IsPlayable = true, IsConfigurable = false };
}


内部设置器和只读接口应足以确保未在插件程序集外部修改属性。

关于c# - 使用类描述C#中的数据,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15894022/

10-09 08:18