我正在尝试为一类对象列表创建别名。具体来说,我想缩短我必须为这种类型做的所有打字:
IReadOnlyList<IReadOnlyList<MyObject>>
我的尝试在这里得到证明:
using System.Collections.Generic;
namespace MyApp
{
class Program
{
public class MyObject
{
public static IMyCollection GetCollection()
{
var a = new List<MyObject>();
a.Add(new MyObject());
var b = new List<IReadOnlyList<MyObject>>();
b.Add(a.AsReadOnly());
return b.AsReadOnly();
}
}
public interface IMyCollection : IReadOnlyList<IReadOnlyList<MyObject>>
{
}
static void Main(string[] args)
{
var collection = MyObject.GetCollection();
}
}
}
不幸的是,这不会编译。错误是:
Cannot implicitly convert type
'System.Collections.ObjectModel.ReadOnlyCollection<System.Collections.Generic.IReadOnlyList<MyApp.Program.MyObject>>'
to 'MyApp.Program.IMyCollection'.
An explicit conversion exists (are you missing a cast?)
好的,我结束了。或许明确地投射?所以我将GetCollection
中的return语句更改为
return (IMyCollection)b.AsReadOnly();
编译,虽然有一个resharper警告:可疑演员:解决方案中没有任何类型继承自SystemCollections.ObjectModel.ReadOnlyCollection&gt;&#39;和&#39; MyApp.Program.IMyCollection&#39;
在运行时,我得到一个无效的强制转换异常:无法强制转换类型&#39; System.Collections.ObjectModel.ReadOnlyCollection 1[System.Collections.Generic.IReadOnlyList
1 [MyApp.Program + MyObject]]&#39;输入&#39; IMyCollection&#39;。
如何创建名称非常长的类型并转换为名称非常短的类型?
更新:
一位同事建议使用using
声明。
using IMyCollection= System.Collections.Generic.IReadOnlyList<System.Collections.Generic.IReadOnlyList<MyApp.Program.MyObject>>;
虽然这样可行,但有必要在使用IMyCollection
的每个文件中执行此操作。不完全是我认为我的目标的解决方案。
答案 0 :(得分:4)
你有多想要这个?
您可以手动实现自己的包装类。
public interface IMyCollection : IReadOnlyList<IReadOnlyList<MyObject>>
{
}
public class MyCollectionImpl : IMyCollection
{
private readonly IReadOnlyList<IReadOnlyList<MyObject>> _wrappedCollection;
public MyCollectionImpl(IReadOnlyList<IReadOnlyList<MyObject>> wrappedCollection)
{
_wrappedCollection = wrappedCollection;
}
public int Count
{
get
{
return _wrappedCollection.Count;
}
}
public IReadOnlyList<MyObject> this[int index]
{
get
{
return _wrappedCollection[index];
}
}
public IEnumerator<IReadOnlyList<MyObject>> GetEnumerator()
{
return _wrappedCollection.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _wrappedCollection.GetEnumerator();
}
}
然后你只需创建一个这样的实例:
public class MyObject
{
public static IMyCollection GetCollection()
{
var a = new List<MyObject>();
a.Add(new MyObject());
var b = new List<IReadOnlyList<MyObject>>();
b.Add(a.AsReadOnly());
return new MyCollectionImpl(b.AsReadOnly());
}
}
这似乎是一项额外的工作,但实际上我认为这是一个重构步骤。
我认为需要传递由复杂的通用参数组成的类型,实际上是代码中的难闻气味。
问问自己,您实际使用IMyCollection
的目的是什么?您是否可以在此界面中添加一些专门的方法以使其更易于使用?
创建自己的MyCollectionImpl
课程后,您可以在IMyCollection
界面中慢慢添加多种方法,以简化其使用。在某些时候,您甚至可能会进入可以停止公开<IReadonlyList<IReadonlyList<MyObject>>
界面的阶段。
答案 1 :(得分:3)
这与协方差无关。 IMyCollection
继承自IReadOnlyList<IReadOnlyList<MyObject>>
,因此您可以将IMyCollection
的实例投射到IReadOnlyList<IReadOnlyList<MyObject>>
,但不能反过来。
如果您想要进行一些自定义转换,那么您可以使用所需的短名称创建一个类型,并使用operator overloading
声明从IReadOnlyList<IReadOnlyList<MyObject>>
到您的类型的转换。这似乎是使用运算符重载的不必要和不寻常的方式,但它是你想要实现的唯一方法。