如何声明带Dictionary值带类型参数

lgg06 2011-04-25 03:56:20
标题可能不贴切(确实想不到贴切的词),上段代码大家应该能明白我想问什么了:
public class Manager
{
private Dictionary<Type, Collection<Person>> mDic = new Dictionary<Type, Collection<Person>>();

public void Add<T>(Collection<T> value) where T : Person
{
mDic.Add(typeof(T), value);
}

public Collection<T> Get<T>(T owner) where T : Person
{
var value = mDic[typeof(T)];
return value;
}
}

public class Collection<T> where T : Person
{
}

public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}

public class Employee : Person
{
}


上面的代码会得到以下的编译错误:
Error 3 Argument 2: cannot convert from 'Collection<T>' to 'Collection<Person>'

问题好像很显然, 虽然Employee继承自Person, 但Collection<Person> 跟 Collection<Employee> 确实没有啥继承上的关系。
我的问题是: 如何解决上面的编译错误?
Manager肯定是不能带类型参数(T)的, 带了也没用
...全文
337 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
lgg06 2011-05-09
  • 打赏
  • 举报
回复
感谢各位的友情帮助。 实际项目中情况更复杂些,最终是通过定义接口实现, 类似于public class Collection<T> : IEnumerable<T>的想法。
Icedmilk 2011-04-26
  • 打赏
  • 举报
回复
刚才想了想,实际上你就这么写

            public Collection<T> Get<T>(T owner) where T : Person
{
var value = mDic[typeof(T)];
return (Collection<T>)value;
}


五楼的方法貌似行不通,实际上是不需要Cast的类型的转换不是出在那个Collection的元素上
而是Collection本身

不过我还是觉得你的设计有点问题
Icedmilk 2011-04-26
  • 打赏
  • 举报
回复
用IEnumerable<T>仍然不能解决问题
因为IEnumerable<Person>和IEnumerable<Employee>依然没有继承关系

所以你就只能用Dictionary<Type, object>
cjh200102 2011-04-26
  • 打赏
  • 举报
回复
楼上都不错。

lgg06 2011-04-26
  • 打赏
  • 举报
回复
public class Collection<T> : IEnumerable<T> where T : Person 可以工作[Quote=引用 18 楼 icedmilk 的回复:]

用IEnumerable<T>仍然不能解决问题
因为IEnumerable<Person>和IEnumerable<Employee>依然没有继承关系

所以你就只能用Dictionary<Type, object>
[/Quote]
lgg06 2011-04-25
  • 打赏
  • 举报
回复
大家好像都挺推荐 5楼地,恕小弟愚笨,木有看出行道啊

value.Cast<T> value应该要继承自IEnumerable的吧, 转型后的类型能是Collection<T>, 不太懂明天试试
lgg06 2011-04-25
  • 打赏
  • 举报
回复
@fangxinggood 你这个方案挺好的,看上去比用object舒服多了:)
lgg06 2011-04-25
  • 打赏
  • 举报
回复
@535cheng110, 谢谢回复,Manager不能带T, 带T也是不能解决这个问题

下面代码编译是过不了的:
manager.Add(new Collection<Person>());
manager.Add(new Collection<Employee>());
535cheng110 2011-04-25
  • 打赏
  • 举报
回复
知道是不是你想要的

public class Manager<T>
where T :class
{
private Dictionary<Type, Collection<T>> mDic = new Dictionary<Type, Collection<T>>();

public void Add(Collection<T> value)
{
mDic.Add(typeof(T), value);
}

public Collection<T> Get(T owner)
{
Collection<T> value = mDic[typeof(T)];
return value;
}
}

public class Collection<T>
{
}

public class Person
{
private string _firstName;
public string FirstName
{
get { return _firstName; }
set { _firstName = value; }
}

private string _lastName;
public string LastName
{
get { return _lastName; }
set { _lastName = value; }
}
}

public class Employee : Person
{
}


机器人 2011-04-25
  • 打赏
  • 举报
回复
还是逆变和协变,用接口来定义Dictionary 可以解决。


 public class Manager
{
private Dictionary<Type, IEnumerable<Person>> mDic = new Dictionary<Type, IEnumerable<Person>>();

public void Add<T>(IEnumerable<T> value) where T : Person
{
mDic.Add(typeof(T), value);
}

public MyCollection<T> Get<T>() where T : Person
{
var value = mDic[typeof(T)];
return (MyCollection<T>)value;
}
}


public class MyCollection<T> : IEnumerable<T> where T : Person
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 include_me 的回复:]
C# code

using System.Linq;

//..

public Collection<T> Get<T>(/* T owner */) where T : Person
{
if (mDic.ContainsKey(typeof(T)){
var value = mDic[typeof(T)];
if(value != null) return va……
[/Quote]

object这种类型放到泛型里容易出问题
同楼上,你可以用泛型约束于你的接口
Directory<T, List<T>> GetPerson<T>() where T : I接口
就是5楼那样的
vrhero 2011-04-25
  • 打赏
  • 举报
回复
转换,感觉设计有点问题...
return new Collection<T>(value.Cast<T>().ToList());
Icedmilk 2011-04-25
  • 打赏
  • 举报
回复
你可以把这样声明 Dictionary<Type, object>

不过用5楼的方法确实可以保持Mananger对外看起来是强类型的。

[Quote=引用 5 楼 include_me 的回复:]
C# code

using System.Linq;

//..

public Collection<T> Get<T>(/* T owner */) where T : Person
{
if (mDic.ContainsKey(typeof(T)){
var value = mDic[typeof(T)];
if(value != null) return va……
[/Quote]
lgg06 2011-04-25
  • 打赏
  • 举报
回复
一开始我也想到协变和逆变, 但查了下资料,发现跟他们末有关系。

协变逆变只适用于接口 和 delegate 上
lgg06 2011-04-25
  • 打赏
  • 举报
回复
谢谢各位的回复。 我想问题本质就在于Collection<Employee> 并非继承自Collection<Person>. 所以按照如下的Dictionary声明, 我们是不能把Collection<Employee> 加进去的:
private Dictionary<Type, Collection<Person>> mDic = new Dictionary<Type, Collection<Person>>();


Collection这里是个特殊的类, 所以不能用ArrayList或者List<T> 代替。 我想你们的意思是不是让Collection<T> 继承自某个接口,或者啥:
如 Collection<T> :ICollection. 不过这样的或就失去了T类型的信息,跟将Dictionary声明成如下,没有太多区别了:private Dictionary<Type, object> mDic = new Dictionary<Type, object>();
Icedmilk 2011-04-25
  • 打赏
  • 举报
回复
楼主的问题是出在这一句上
public void Add<T>(Collection<T> value) where T : Person
{
mDic.Add(typeof(T), value);
}

如果T是Employe的话他连Add的参数类型都不能匹配,何况他这个便宜都通不过
Collection<T> value不符合Dictionary<Type, Collection<Person>的Add方法的参数

[Quote=引用 5 楼 include_me 的回复:]
C# code

using System.Linq;

//..

public Collection<T> Get<T>(/* T owner */) where T : Person
{
if (mDic.ContainsKey(typeof(T)){
var value = mDic[typeof(T)];
if(value != null) return va……
[/Quote]
include_me 2011-04-25
  • 打赏
  • 举报
回复
可参见 C# 4.0 协变和逆变。
include_me 2011-04-25
  • 打赏
  • 举报
回复

using System.Linq;

//..

public Collection<T> Get<T>(/* T owner */) where T : Person
{
if (mDic.ContainsKey(typeof(T)){
var value = mDic[typeof(T)];
if(value != null) return value.Cast<T>();
return null;
}
}
effun 2011-04-25
  • 打赏
  • 举报
回复
仅供参考


class Manager
{
private Dictionary<Type, List<Person>> mDic = new Dictionary<Type, List<Person>>();

public void Add(IEnumerable<Person> coll)
{
foreach (Person p in coll)
{
Type t = p.GetType();
List<Person> list;

if (!mDic.TryGetValue(t, out list))
{
list = new List();
mDic.Add(t, list);
}
list.Add(p);
}
}

public T[] Get<T>() where T: Person
{
Type t = typeof(T);
List<Person> list;

if (mDic.TryGetValue(t, out list))
return list.Cast<T>().ToArray();
else
return new T[0];
}
}

Icedmilk 2011-04-25
  • 打赏
  • 举报
回复
我感觉没有什么更好的方法了吧

你也知道Collection<Person> 跟 Collection<Employee> 没啥继承关系,那还要用一个Dictionary同时放这两种东西,只有使用Dictionary<Type, object>了

或者干脆不要把Collection写成模板了,直接用ArrayList

[Quote=引用 1 楼 lgg06 的回复:]
下面是我目前能想到的方案,只是感觉不够“强类型”, 肯定有其他更好的解决方案:

C# code

public class Manager
{
private Dictionary<Type, object> mDic = new Dictionary<Type, object>();

public void Add<T>(Collection<T> value……
[/Quote]
加载更多回复(2)

110,533

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧