通过 IList 对通用列表进行后门处理

发布于 2024-10-01 18:59:47 字数 835 浏览 5 评论 0原文

我有一个场景,一个类加载一种类型的对象,由于抽象,我不能使用泛型类(泛型往往像癌症一样传播:),但我经常想在检索到对象后使用泛型版本,这导致在这样的代码中(简化):

List<SomeClass> items = Storage.LoadItems(filename).OfType<SomeClass>().ToList();

其中 LoadItems 返回一个 List,然后我意识到,为什么不改为

public void LoadItems(string filename,IList list);

现在我可以这样做,

List<SomeClass> items = new  List<SomeClass>();
LoadItems(filename,items);

这应该更有效。它似乎也更灵活一些,因为我可以采用现有列表并添加新项目。所以我的问题是,这是一种常见模式还是您有不同/更好的方法来实现这一目标?

我也有点好奇你可以这样做,如果你尝试添加错误类型的对象,你会得到一个异常,但这是否意味着通用列表也会进行类型检查? (这似乎有点不必要)

编辑 实际上,修改模式可能会更优雅一些,这样

public IList LoadItems(string filename,IList list=null);

您就可以流畅地使用语句,并且如果没有传递列表,您可以简单地实例化一个 List

I have a scenario where a class loads objects of one type, due do abstractions I can not use a generic class (generics tend to spread like cancer :) but I often want to work with a generic version of the objects once retrieved, which resulted in code like this (simplified):

List<SomeClass> items = Storage.LoadItems(filename).OfType<SomeClass>().ToList();

Where LoadItems returns a List<object>, then I realized, why not instead have

public void LoadItems(string filename,IList list);

Now I can do this instead

List<SomeClass> items = new  List<SomeClass>();
LoadItems(filename,items);

Which should be more efficient. It's also seems a bit more flexible since I can take an existing List and tack on new items. So my questions are, is this a common pattern or do you have a different/better way of achieving this?

I'm also a bit curious that you can do this, if you try and add a object of the wrong type you get an exception, but does that mean that generic lists also do a type check? (which seems a bit unecessary)

EDIT
It might actually be a bit more elegant to modify the pattern to

public IList LoadItems(string filename,IList list=null);

that way you can use the statement fluently and if no list is passed you could simply instantiate a List<object>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

一个人的夜不怕黑 2024-10-08 18:59:48

List 显式实现 IList
实现强制转换为 T 并调用常规(通用)方法。

因此,只有在显式调用 IList 方法时才会进行类型检查。
例如:

void System.Collections.IList.Insert(int index, Object item) 
{
    ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(item, ExceptionArgument.item); 

    try {
        Insert(index, (T) item); 
    }
    catch (InvalidCastException) {
        ThrowHelper.ThrowWrongValueTypeArgumentException(item, typeof(T));
    } 
}

它不使用 as 关键字,因为 T 可能是值类型。
如果您写的是 where T : class,则只能写成 as T

List<T> implements IList explicitly.
The implementations cast to T and call the regular (generic) methods.

Thus, type-checking only happens if you explicitly call the IList methods.
For example:

void System.Collections.IList.Insert(int index, Object item) 
{
    ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(item, ExceptionArgument.item); 

    try {
        Insert(index, (T) item); 
    }
    catch (InvalidCastException) {
        ThrowHelper.ThrowWrongValueTypeArgumentException(item, typeof(T));
    } 
}

It doesn't use the as keyword because the T might be a value type.
You can only write as T if you wrote where T : class.

じ违心 2024-10-08 18:59:48

在大多数情况下,使用 IList 就可以了;并且当然比使用反射或动态来实现相同的效果更快。

是的,它会添加类型检查(通过强制转换/拆箱),但这不会很麻烦。如果 T 是一个 struct 那么你也会有一些装箱/拆箱,但这也没有人们担心的那么糟糕。

在这种情况下,IList 对我来说就很好。

Using IList is fine in most cases; and is certainly faster than using reflection or dynamic to achieve the same.

Yes it will add a type-check (by virtue of the cast/unbox), but that will not be onerous. If T is a struct then you also have some boxing/unboxing, but that too isn't as bad as people fear.

In that scenario, IList would be fine by me.

小糖芽 2024-10-08 18:59:48

您的解决方案看起来确实不错,没有任何问题。

关于Add,它并没有真正进行类型检查。您引用的 Add 的代码是这样的:

int System.Collections.IList.Add(Object item)
{
    try {
        Add((T) item);
    }
    catch (InvalidCastException) {
        throw ...;
    }

    return Count - 1;
}

它不进行类型检查;这只是一个尝试/捕获。

Your solution does look sound, there is nothing wrong with it.

Concerning the Add, it doesn't really do a type check. The code for the Add you refer to is this:

int System.Collections.IList.Add(Object item)
{
    try {
        Add((T) item);
    }
    catch (InvalidCastException) {
        throw ...;
    }

    return Count - 1;
}

It doesn't do a type check; it's just a try/catch.

清眉祭 2024-10-08 18:59:48

我喜欢第二种方法。

您可以传递 IList,但然后检查类型以查看它是否是通用列表,如果是,则获取通用类型并仅加载该类型的记录:

   Type itemType = typeof (object);
   if(list.GetType().GetGenericArguments().Length>0)
   {
       itemType = list.GetType().GetGenericArguments()[0];
   }

   for (int i = 0; i < recordCount; i++)
   {
      if(record.GetType().IsInstanceOfType(itemType))
   }

I like the second approach.

You can pass the IList but then check the type to see if it is a generic list and if so, get generic type and load only records of that type:

   Type itemType = typeof (object);
   if(list.GetType().GetGenericArguments().Length>0)
   {
       itemType = list.GetType().GetGenericArguments()[0];
   }

   for (int i = 0; i < recordCount; i++)
   {
      if(record.GetType().IsInstanceOfType(itemType))
   }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文