C# 只读集合属性的类设计
我有一个C# 只读集合属性的类设计,c#,C#,我有一个IDictionary集合,需要将它传递给一个类,以便将其包装成IReadOnlyDictionary(注意MyEnum,但不是MyEnum?) 我提出了两种设计: 延迟包装到IReadOnlyDictionary,直到属性访问: public class MyClass { private readonly IEnumerable<KeyValuePair<string, MyEnum?>> _kvps; public MyClass(IEnu
IDictionary
集合,需要将它传递给一个类,以便将其包装成IReadOnlyDictionary
(注意MyEnum
,但不是MyEnum?
)
我提出了两种设计:
IReadOnlyDictionary
,直到属性访问:
public class MyClass
{
private readonly IEnumerable<KeyValuePair<string, MyEnum?>> _kvps;
public MyClass(IEnumerable<KeyValuePair<string, MyEnum?>> kvps)
{
_kvps = kvps;
}
public IReadOnlyDictionary<string, MyEnum> Kvps
{
get
{
var filtered = from kvp in _kvps
where kvp.Value.HasValue
select kvp;
return new ReadOnlyDictionary<string, MyEnum>(
filtered.ToDictionary(kvp => kvp.Key, kvp => (MyEnum)kvp.Value);
}
}
}
公共类MyClass
{
私有只读IEnumerable_kvps;
公共MyClass(IEnumerable kvps)
{
_kvps=kvps;
}
公共IReadOnlyDictionary Kvps
{
得到
{
过滤的var=来自kvp中的_kvps
其中kvp.Value.HasValue
选择kvp;
返回新的ReadOnlyDictionary(
ToDictionary(kvp=>kvp.Key,kvp=>(MyEnum)kvp.Value);
}
}
}
public class MyClass
{
public MyClass(IEnumerable<KeyValuePair<string, MyEnum?>> kvps)
{
Kvps = ToReadOnly(kvps);
}
public IReadOnlyDictionary<string, MyEnum> Kvps { get; }
private static IReadOnlyDictionary<string, MyEnum> ToReadOnly(
IEnumerable<KeyValuePair<string, MyEnum?>> kvps)
{
var filtered = from kvp in kvps
where kvp.Value.HasValue
select kvp;
return new ReadOnlyDictionary<string, MyEnum>(
filtered.ToDictionary(kvp => kvp.Key, kvp => (MyEnum)kvp.Value);
}
}
公共类MyClass
{
公共MyClass(IEnumerable kvps)
{
Kvps=toreadoly(Kvps);
}
公共IReadOnlyDictionary Kvps{get;}
私有静态IReadOnlyDictionary ToReadOnly(
IEnumerable(kvps)
{
过滤的var=来自kvp(单位:kvps)
其中kvp.Value.HasValue
选择kvp;
返回新的ReadOnlyDictionary(
ToDictionary(kvp=>kvp.Key,kvp=>(MyEnum)kvp.Value);
}
}
MyClass.Kvps
都会触发\u Kvps
的副本,这并不理想
我想知道在以下方面哪种方法更好(或有其他方法):
- 内存效率(理想情况下,只有一个集合副本存储在
)MyClass
- 性能(属性访问应快速,且不应触发
s)的副本)KeyValuePair
IReadOnlyDictionary
。使用ReadOnlyDictionary
的私有字段初始化它。每次调用都会进行查找,如果键存在并且HasValue
,则返回值
请注意,此实现依赖于作为IReadOnlyDictionary
传入的原始值的引用,以避免复制值
公共类MyReadOnlyDictionary:IReadOnlyDictionary,其中TValue:struct
{
//这里要实现的其他方法。。。
公共MyReadOnlyDictionary(IReadOnlyDictionary kvps)
{
_kvps=kvps;
}
私人IREADONLYDICTIONAL kvps;
新的公共TValue此[TKey]
{
得到
{
TValue?val=_kvps[键];
if(val.HasValue)
返回值;
抛出新的KeyNotFoundException();
}
}
}
在这两个要求中—不要复制键值对,也不要存储两个副本—您必须断开一个
让我们看到这一点并认为一定有解决办法的原因是,我们看到了TValue
和TValue?
,我们的大脑希望看到它们属于同一类型,但它们不是同一类型
如果您设想这是两种不同的类型,而不是TValue
和TValue?
,例如int
和string
,我们希望在过滤时将一种类型的集合投影到另一种类型的集合,那么情况就更清楚了。例如
List<string> GetStringsFromNonNegativeInts(List<int> ints)
{
return ints.Where(i=>i>-1).Select(i=>i.ToString()).ToList();
}
List GetStringsFromNonNegativeInts(List ints)
{
返回int.Where(i=>i>-1);
}
这与尝试将一组TValue?
过滤为一组TValue
完全相同,即使没有字典也一样。这更难看到。TValue
和TValue?
代码使我们失明
只有两种方法可以做到这一点。一种是每次复制,另一种是保持两个列表同步。如果在构造和属性访问之间或在连续属性访问之间修改源词典,则您的两个设计会有不同的行为。您想要哪种方法?@Blorgbeard我想将属性设置为always反映源代码
IDictionary
中的最新值。这是否意味着我仅限于我的第一种方法?然后是的,您必须在属性访问器中进行筛选。除非您编写自己的IReadOnlyDictionary
类来包装源代码。那么至少您只有一个数据副本,但您有要进行的ore筛选(几乎所有自定义IReadOnlyDictionary上的属性访问)@Blorgbeard我同意这可能是最好的方法。但是,如果将对值的引用作为IDictionary
传入,则可以最小化筛选。OP在其评论中表示,他希望在每次调用属性时都使用最新的源值,因此缓存将不起作用。很好的一点。我更新了答案以反映这一点。我认为c上面提到的关于实现一个新的IReadOnlyDictionary实现类是最有效的方法。我也研究了这种方法。处理枚举数似乎很痛苦,因为你不得不“假装”有些条目实际上不在词典中。@ScottHannen这取决于您如何看待它。对于使用此只读词典的用户来说,一个带有空值的条目对他们来说并不存在,也就是说,它对他们没有任何用处,他们可能会忽略它。这个新类只是一个映射来反映这一点。我们不从这个意义上说,我们可以对他们“隐藏”任何他们无论如何都不会忽略的东西。它只是封装了忽略空值的逻辑。必须通过实现IReadOnlyDictionary
并测试它的行为来证明这一点
List<string> GetStringsFromNonNegativeInts(List<int> ints)
{
return ints.Where(i=>i>-1).Select(i=>i.ToString()).ToList();
}