C# 在C语言中处理可变集合键#
假设我在C#中有一个简单的类C# 在C语言中处理可变集合键#,c#,.net,collections,class-design,C#,.net,Collections,Class Design,假设我在C#中有一个简单的类Cat,其Name属性的类型为string。现在,我需要为我的猫创建一个集合类,所以我决定在自定义集合类中包装一个字典。基本上,此类保存一个私有字典变量,并根据需要添加或删除集合成员,以及按名称索引CAT: class Cats { private Dictionary<string, Cat> m_dic = new Dictionary<string,Cat>(); public void Add(Cat c) {
Cat
,其Name
属性的类型为string
。现在,我需要为我的猫创建一个集合类,所以我决定在自定义集合类中包装一个字典。基本上,此类保存一个私有字典变量,并根据需要添加或删除集合成员,以及按名称索引CAT:
class Cats
{
private Dictionary<string, Cat> m_dic = new Dictionary<string,Cat>();
public void Add(Cat c)
{
m_dic.Add(c.Name, c);
}
public void Remove(string name)
{
m_dic.Remove(name);
}
public Cat this[string name]
{
get
{
return m_dic[name];
}
}
}
我可以从它的名字中找到一只猫:
Cat c1 = cs["Sophie"];
这一切都很好。问题是,当我改变猫的名字时,就像这样:
Cats cs = new Cats();
cs.Add(new Cat("Valentina"));
cs.Add(new Cat("Sophie"));
cs.Add(new Cat("Tomboy"));
c1.Name = "Sofia";
class Cats
{
private Dictionary<string, INotifyPropertyChanged> m_dic =
new Dictionary<string, INotifyPropertyChanged>();
public void Add(INotifyPropertyChanged obj)
{
m_dic.Add(obj.Name, obj);
}
public void Remove(string name)
{
m_dic.Remove(name);
}
public INotifyPropertyChanged this[string name]
{
get { return m_dic[name]; }
}
}
class NotificationDictionary
{
private Dictionary<string, INotificationKey> m_dic =
new Dictionary<string, INotificationKey>();
public void Add(INotificationKey obj)
{
m_dic.Add(obj.Key, obj);
}
public void Remove(string key)
{
m_dic.Remove(key);
}
public INotificationKey this[string key]
{
get { return m_dic[key]; }
}
}
…显然,c1
引用的对象的集合键没有更新。因此,如果我尝试使用同一项的新名称检索该项,则会出现异常:
Cat c2 = cs["Sofia"]; //KeyNotFoundException is thrown here.
这是运行时正确而明显的行为。我的问题是:您能否建议一种优雅可靠的方法,在元素的name属性发生更改时更改集合键
我的目标是能够在任何时候从名称中检索项目,正如您所想象的那样。我通过让Name
属性的setter引发一个事件来解决这个问题,这样持有该对象的任何集合都可以更新相应的键。不过,这种方法相当麻烦,效率也不高
你能想出更好的吗?谢谢。您的收藏将有多大,以及能够通过索引检索项目有多重要
如果它相对较小(几百个,而不是几千个),您最好使用列表
,并使用新的LINQ扩展方法访问它们,如:
public Cat this[string name]{
get{
//Will return the first Cat in the list (or null if none is found)
return m_List.Where(c => c.Name == name).FirstOrDefault();
}
}
添加(和删除)也很简单:
public void Add(Cat c){
m_List.Add(c);
}
如果这对你不起作用,请告诉我。希望这有帮助 您还可以在Cat上放置回调,以便在其Name属性更改时通知您的集合
…通过设置名称
属性引发事件
你是说像这样的事吗
c1.Name = "Sofia";
NameChangedEventHandler handler = NameChangedEvent;
if (handler != null)
{
handler(c1, new NameChangedEventArgs("Sophie", "Sophia"));
}
这就是你所说的让二传手发起一场比赛的意思吗?如果是这样,那么我建议将其移动到Cat
类的Name
属性设置器。没有理由要求二传手像这样发起比赛。当Cat
的名称通过公共属性更改时,应隐式执行此操作
对我来说,这是一个优雅的解决方案;它只是不符合字典
集合的工作方式。我不知道这本身就是个问题,但它确实将Cats
集合与Cat
类紧密耦合
请记住,您可能需要实现许多与genericDictionary
类相同的接口。否则,Cats
集合将在某些方面类似于字典
,但并不完全相同
编辑:这是对您的评论的回应。我希望我能更清楚地表达我的想法。我的目的是改进你的设计
我同意,一般来说,事件确实提供了更松散的耦合。但是,在这种情况下,Cats
集合仍然与Cat
类紧密耦合,因为集合正在注册由特定类型的类公开的特定类型的事件
那么,如何改进这一点呢
改进这一点的简单方法是让Cat
类实现在接口中定义的事件。NET为这个明确的目的提供了这样一个接口,System.ComponentModel
命名空间中的接口。通过在Cat
类中实现此接口,这将允许Cat
集合包装器定义如下:
Cats cs = new Cats();
cs.Add(new Cat("Valentina"));
cs.Add(new Cat("Sophie"));
cs.Add(new Cat("Tomboy"));
c1.Name = "Sofia";
class Cats
{
private Dictionary<string, INotifyPropertyChanged> m_dic =
new Dictionary<string, INotifyPropertyChanged>();
public void Add(INotifyPropertyChanged obj)
{
m_dic.Add(obj.Name, obj);
}
public void Remove(string name)
{
m_dic.Remove(name);
}
public INotifyPropertyChanged this[string name]
{
get { return m_dic[name]; }
}
}
class NotificationDictionary
{
private Dictionary<string, INotificationKey> m_dic =
new Dictionary<string, INotificationKey>();
public void Add(INotificationKey obj)
{
m_dic.Add(obj.Key, obj);
}
public void Remove(string key)
{
m_dic.Remove(key);
}
public INotificationKey this[string key]
{
get { return m_dic[key]; }
}
}
请注意,INotificationKey
接口继承自INotifyPropertyChanged
接口,该接口允许按如下方式定义集合包装:
Cats cs = new Cats();
cs.Add(new Cat("Valentina"));
cs.Add(new Cat("Sophie"));
cs.Add(new Cat("Tomboy"));
c1.Name = "Sofia";
class Cats
{
private Dictionary<string, INotifyPropertyChanged> m_dic =
new Dictionary<string, INotifyPropertyChanged>();
public void Add(INotifyPropertyChanged obj)
{
m_dic.Add(obj.Name, obj);
}
public void Remove(string name)
{
m_dic.Remove(name);
}
public INotifyPropertyChanged this[string name]
{
get { return m_dic[name]; }
}
}
class NotificationDictionary
{
private Dictionary<string, INotificationKey> m_dic =
new Dictionary<string, INotificationKey>();
public void Add(INotificationKey obj)
{
m_dic.Add(obj.Key, obj);
}
public void Remove(string key)
{
m_dic.Remove(key);
}
public INotificationKey this[string key]
{
get { return m_dic[key]; }
}
}
类通知字典
{
私人词典=
新字典();
公共作废添加(INotificationKey obj)
{
m_dic.Add(obj.Key,obj);
}
公共无效删除(字符串键)
{
拆卸(钥匙);
}
public INotificationKey此[字符串键]
{
获取{return m_dic[key];}
}
}
这是一个更加灵活的解决方案。但它仍有不足之处,因为它不像字典那样完全发挥作用。例如,根据定义,NotificationDictionary
类不能用于foreach
迭代,因为它没有实现IEnumerable
接口
要成为真正优雅的解决方案,集合的行为应该像一个字典
。这需要在前端多做一点努力,但在后端,您会有一个足够灵活的解决方案,可以适应各种情况。嘿,谢谢。我知道列表只通过int索引,所以使用Where这样的方法应该效率很低,对吗?我不希望有非常大的集合,所以这可能会起作用。“按int索引”应该是“按位置索引”;在我看来,pIt不是一个可怕的解决方案。正如我在回答中提到的,集合的大小将影响对象访问的速度。此外,如果列表非常大,并且您连续多次搜索某个元素,那么访问频率可能会对性能产生负面影响。我将尝试想出另一个与您的原始示例类似的解决方案!我在问题中解释说,我尝试让Cat在名称更改时引发一个事件,集合通过更新密钥来响应该事件。这就是你的意思吗?:-)我所做的(以及我在问题中试图解释的)正是您所建议的:从Cat的public Name属性中的set块引发事件。:-)耦合是可以的,因为毕竟事件并没有那么多地耦合类。收藏是免费的