请注意以下代码:
public class MyClass
{
List<object> _List = new List<object>();
public List<object> Objects { get { return _List; } }
public List<string> Strings { get { return _List.Cast<string>().ToList(); } }
public void Test()
{
Objects.Add ("Hello");
// actual contents
// Objects = object[] { "Hello" }
// Strings = string[] { "Hello" }
Strings.Add ("World");
// actual contents
// Objects = object[] { "Hello" }
// Strings = string[] { "Hello" }
// expected contents
// Objects = object[] { "Hello", "World" }
// Strings = string[] { "Hello", "World" }
}
}
代码显示了一个包含对象列表的类。这两个属性分别将该列表公开为List<object>
和List<string>
。但是,由于_List.Cast<string>().ToList()
创建了实际列表的COPY,因此行Strings.Add ("World")
不会影响实际列表。有没有办法确保在Strings
属性中返回实际列表的CASTED REFERENCE而不是实际列表的CASTED COPY?
注意:当一个整数添加到Objects
然后从Strings
访问时,代码可能会失败,但这不是我现在担心的。
修改
原始问题如下。它被改变以避免混淆并简化手头的问题。请注意以下代码:
public abstract class Foo
{
List<object> _List = new List<object>();
public List<object> ListObject { get { return _List; } }
}
public class Bar : Foo
{
public List<string> ListString
{
get { return ListObject.Cast<string>().ToList(); }
}
}
Bar oBar = new Bar();
Foo oFoo = oBar;
oFoo.ListObject.Add("Item");
// oFoo.ListObject= { "Item" }
// oBar.ListString = { "Item" }
oBar.ListString.Add("NewItem");
// oFoo.ListObject= { "Item" }
// oBar.ListString = { "Item" }
正如您所看到的,使用基类对象可以正常工作(项目被添加到内部列表中),但使用派生类对象不起作用。我知道原因是因为将List转换为List实际上会创建一个列表的新副本并返回该列表。我想知道是否可以编写这些类,以便它可以双向工作。
答案 0 :(得分:2)
您可以尝试这样的事情:
public abstract class Foo<T>
{
List<T> _List = new List<T>();
public List<T> ListObject { get { return _List; } }
}
public class Bar : Foo<string>
{
public List<string> ListString
{
get { return ListObject; }
}
}
结果:
答案 1 :(得分:2)
我希望其他人会对此提出一个相当不错的答案,但现实情况是,这个答案可能没有好的答案。
然而,有几种方法可以给你的普通猫提供皮肤,其中很多都非常难看。
这个问题的一个丑陋的解决方案是实现一个封装n List<object>
对象的列表类,并尝试以您选择的任何类型访问对象。这种类型的代理类可能很难做到正确,但可能是你想要做的事情的一种方式。
public class StringObjectList : IList<string>
{
private List<object> _list;
public StringObjectList(List<object> src)
{
_list = src;
}
// IList Implementation...
public string this[int index]
{
get
{
object obj = _list[index];
if (obj == null)
return null;
return obj.ToString();
}
set
{
_list[index] = value;
}
}
// ... plus 3 more IList<string> methods (IndexOf, Insert, RemoveAt)
// ICollection<string> implementation (5 methods, 2 properties)
// IEnumerable<string> implementation (1 method)
// IEnumerable implementation (1 method)
}
一些实施细节有点棘手。虽然实现是简单的代理方法,但主要是因为底层列表很乐意接受字符串以及任何其他对象。例如ICollection<string>.Add
方法可以简单如下:
public void Add(string item)
{
_list.Add(item);
}
您可能遇到问题的地方是IEnumerable<string>
和IEnumerable
实施,这可能需要您创建一些支持类。
不简单,不优雅,但可能是可行的。
答案 2 :(得分:0)
如果您不喜欢上面的通用解决方案,可以将List
成员抽象化。
public abstract class Foo
{
public abstract IList ListObject { get; }
}
public class Bar : Foo
{
public override IList ListObject
{
get { return new List<string>(); }
}
}
答案 3 :(得分:0)
public abstract class Foo<T>
{
public abstract IList<T> MyList { get; }
// you can manipulate MyList in this class even if it is defined in inherited class
}
public class Bar : Foo<string>
{
private readonly IList<string> _myList = new List<string>();
public override IList<string> MyList
{
get { return _myList; }
}
}
[TestFixture]
public class TestFixture1
{
[Test]
public void Test()
{
Bar oBar = new Bar();
Foo<string> oFoo = oBar;
oFoo.MyList.Add("Item");
// oFoo.ListObject= { "Item" }
// oBar.ListString = { "Item" }
oBar.MyList.Add("NewItem");
// oFoo.ListObject= { "Item" }
// oBar.ListString = { "Item" }
}
}