C# 在字典中选择并删除特定对象类型的最有效方法

C# 在字典中选择并删除特定对象类型的最有效方法,c#,linq,collections,C#,Linq,Collections,好的,我有一系列基于基类的对象,它们随机存储在Dictionary对象中。e、 g class TypeA { public int SomeNumber {get; set;} public void SomeFunction() } class TypeB : TypeA { public string SomeString {get; set;} } class TypeC : TypeA { public bool StuffReady() } Dicti

好的,我有一系列基于基类的对象,它们随机存储在Dictionary对象中。e、 g

class TypeA
{
   public int SomeNumber {get; set;}
   public void SomeFunction()
}

class TypeB : TypeA
{
   public string SomeString {get; set;}
}

class TypeC : TypeA
{
   public bool StuffReady()
}


Dictionary listOfClasses <long, TypeA>;
A类
{
公共int SomeNumber{get;set;}
公共函数()
}
B类:A类
{
公共字符串SomeString{get;set;}
}
C类:A类
{
公共图书馆StuffReady()
}
类别词典列表;
键值是已放入字典的对象数的运行计数。它与当前字典计数不匹配

我希望找到一个类型为B的对象,它的SomeString==“123”,然后将其删除。
这样做的最佳方式是什么?

TypeA类和字典键之间似乎没有映射。键的类型为long,并且该类上没有该类型的属性。因此,您必须搜索KeyValuePair实例的集合,这将使您能够直接访问密钥

试试下面的方法

var found = listOfClasses
  .Where(p => p.Value.SomeString == "123").
  .Where(p => p.Value.GetType() == typeof(TypeB))
  .Single();
listOfClasses.Remove(found.Key);

如果您确定只有一个匹配对象(或者如果您只想删除第一个匹配对象):

如果可能存在多个匹配对象,并且您希望将其全部删除:

var query = listOfClasses.Where
    (
        x => (x.Value is TypeB) && (((TypeB)x.Value).SomeString == "123")
    );

// the ToArray() call is required to force eager evaluation of the query
// otherwise the runtime will throw an InvalidOperationException and
// complain that we're trying to modify the collection in mid-enumeration
foreach (var found in query.ToArray())
{
    listOfClasses.Remove(found.Key);
}

您需要在每个对象中存储运行长度。在
TypeA
中添加一个属性,例如
RunningLength
。然后使用两个词典,一个用于存储
TypeA
对象,另一个用于存储
TypeB
对象

每当您创建一个对象(从
TypeA
降下来的任何类型)时,将其添加到第一个字典中。如果创建的对象属于
类型B
请将其添加到第二个字典:

Dictionary listOfClasses <long, TypeA>;
Dictionary listOfTypeBClasses <string, TypeB>;

TypeA newOject = TypeAFactory.Create();

if(newObject is TypeB)
{
  TypeB objB = newObj as TypeB;
  listOfTypeBClasses[objB.SomeString] = objB;
}

如果您是从性能的角度来看,那么for循环是更好的选择,但是如果您是从代码的紧凑性或代码管理的角度来看,那么LINQ就是最佳选择。

我相信性能的差异会非常非常,非常小。在这种情况下,我怀疑LINQ查询和“foreach”循环之间的性能差别很小。(和往常一样,如果性能是一个很大的问题,那么您应该配置/基准测试。)应该只有一个SomeString值为“123”的对象。我将使用相同或类似的代码来确保这一点。编译器不允许对“found”进行null检查,但如果“found”没有值,Remove语句不会引发异常。@ChrisBD:Good catch。如果存在Key=0的合法词典条目,则在未找到项时调用Remove可能会导致问题(因为找不到项时,find.Key的值将默认为0)。我已经更新了代码,对find.Value执行空检查。@Luke。很好的一点,我不确定是否需要检查find.Value,但我同意您对键值可能为0的观察。Thios需要强制转换来访问属性SomeString,然后才能通过编译,但在运行时会引发异常-这与IEnumerable和KeyValue对有关。但它还是让我这么想+1。
Dictionary listOfClasses <long, TypeA>;
Dictionary listOfTypeBClasses <string, TypeB>;

TypeA newOject = TypeAFactory.Create();

if(newObject is TypeB)
{
  TypeB objB = newObj as TypeB;
  listOfTypeBClasses[objB.SomeString] = objB;
}
if(listOfTypeBClasses.ContainsKey("123"))
{
  long keyA = listOfTypeBClasses["123"].RunningLength;
  listOfClasses.Remove(keyA);
  // if required remove the item from listOfTypeBClasses as well
  listOfTypeBClasses.Remove("123");
}