【问题标题】:How to create list of base classes using list of nested classes via generic without casting如何通过泛型使用嵌套类列表创建基类列表而不进行强制转换
【发布时间】:2023-03-25 20:44:01
【问题描述】:

我想要ICollection<T2> 的扩展方法,女巫返回给我IReadOnlyCollection<T1>。为了不在代码中重复自己,我需要所有这些。我有以下代码:

public static IReadOnlyCollection<T1> All<T1, T2>(this ICollection<T2> storage) where T1 : T2
{
    if (storage.Count > 0)
    {
        return new List<T1>(storage);
    }
    else
    {
        return new List<T1>();
    }
}

但不幸的是它没有编译。 所以让我们看一下上面的一个更简单的例子:

public interface IDatabase {}
public class Database : IDatabase, IDisposable {}

public static IReadOnlyCollection<T1> All<T1, T2>(this ICollection<T2> storage) where T2 : T1 where T1 : new()
{
    // compiles
    List<Database> derivedList = new List<PublishedDatabase>();
    List<IDatabase> baseList = new List<IPublishedDatabase>(derivedList);

    // doesn't compile
    // with casting it works
    List<T2> derivedListT = new List<T2>();
    List<T1> baseList1T = new List<T1>(derivedListT/* as IEnumerable<T1>*/);

    //...
}

我可以通过泛型使用嵌套类列表创建基类列表而不进行强制转换吗?

【问题讨论】:

  • 你为什么不想投?
  • 因为我们自己的代码分析器禁止这样做

标签: c# .net generics collections


【解决方案1】:

我可能误解了这里的限制,但您可以暂时使用dynamic欺骗分析器

public static IReadOnlyCollection<T1> All<T1, T2>(this ICollection<T2> storage) where T2: T1
{
    dynamic temp = storage;
    return new ReadOnlyCollection<T1>(new List<T1>(temp));
}

...

var list = new List<SomeChild>()
               {
                  new SomeChild()
               };

var interfaces = list.All<ISomeBase, SomeChild>();

注意:如果您的代码分析器抱怨强制转换,您会认为他们会更加抱怨 dynamic... 也完全未经测试,并且可能有更好的方法来做到这一点

【讨论】:

    【解决方案2】:

    你可以像这样简化扩展方法的代码

    public static IReadOnlyCollection<T1> All<T1>(this ICollection<T1> storage)
            {
                if(storage.Count > 0)
                {
                    return new List<T1>(storage);
                }
                else
                {
                    return new List<T1>();
                }
            }
    

    然后你可以这样称呼它:

    public static void Run()
            {
               ICollection<IDatabase> databases= new List<IDatabase>(){ new Database()};
               databases.All();
            }
    

    【讨论】:

    • 我需要T2T1 因为T2IDisposableT1 不是。所以T2 : T1, IDisposable。我想退回不是一次性的东西。
    猜你喜欢
    • 1970-01-01
    • 2016-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多