我正在用 C# 编写一个支持插件的应用程序。每个插件都必须自我介绍,以便应用程序可以为其准备适当的环境。当前的 info 对象看起来不像这样:
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()
{
// (...)
}
}
}
}
}
有没有优雅的方法来解决这个问题?