从一开始,我就有了一个简单的通用界面:
public interface IItemContainer<T> where T : Item
{
T ChosenItem { get; set; }
}
一个多次实现它的类:
public class ChosenItemsContainer : IItemContainer<FabulousItem>, IItemContainer<NiceItem>, IItemContainer<GreedyItem>
{
public FabulousItem ChosenItem { get; set; }
NiceItem IItemContainer<NiceItem>.ChosenItem { get; set; }
GreedyItem IItemContainer<GreedyItem>.ChosenItem { get; set; }
}
我无法将类型NiceItem和GreedyItem的ChosenItems公开,而且我也无法像这样访问它:
ChosenItem<GreedyItem> = new GreedyItem();
cuz'我有一个错误:
'GreedyItem' is a type, which is not valid in the current context
无论如何以这种方式使用这些道具,或者我已经把它弄错了,应该用词典或其他方式来做?
答案 0 :(得分:2)
如果您希望保留通用IItemContainer,可以像这样实现GetChosenItem和SetChosenItem方法。
public class ChosenItemsContainer : IItemContainer<FabulousItem>, IItemContainer<NiceItem>, IItemContainer<GreedyItem>
{
FabulousItem IItemContainer<FabulousItem>.ChosenItem { get; set; }
NiceItem IItemContainer<NiceItem>.ChosenItem { get; set; }
GreedyItem IItemContainer<GreedyItem>.ChosenItem { get; set; }
public T GetChosenItem<T>()
where T : Item
{
return ((IItemContainer<T>)this).ChosenItem;
}
public void SetChosenItem<T>(T value)
where T : Item
{
((IItemContainer<T>)this).ChosenItem = value;
}
}
这与你想要做的非常接近。
container.SetChosenItem<NiceItem>(new NiceItem());
答案 1 :(得分:2)
你的是一个案例显式接口实现。您为冲突的项目指定唯一名称,并将项目转发到界面。这也避免了任何命名混淆:
public class ChosenItemsContainer : IItemContainer<FabulousItem>, IItemContainer<NiceItem>, IItemContainer<GreedyItem> {
public FabulousItem ChosenFabulousItem { get; set; }
public NiceItem ChosenNiceItem { get; set; }
public GreedyItem ChosenGreedyItem { get; set; }
FabulousItem IItemContainer<FabulousItem>.ChosenItem {
get {
return ChosenFabulousItem;
}
set {
ChosenFabulousItem = value;
}
}
NiceItem IItemContainer<NiceItem>.ChosenItem {
get {
return ChosenNiceItem;
}
set {
ChosenNiceItem = value;
}
}
GreedyItem IItemContainer<GreedyItem>.ChosenItem {
get {
return ChosenGreedyItem;
}
set {
ChosenGreedyItem = value;
}
}
}
作业很简单:
container.ChosenFabulousItem = new FabulousItem();
container.ChosenNiceItem = new NiceItem();
container.ChosenGreedyItem = new GreedyItem();
如果您在后台有更复杂的转换逻辑(例如,您指定了FaboulousItem
并需要将其转换为NiceItem
),则可以通过为您提供getter和/或setter来实现公共财产。
答案 2 :(得分:1)
这是完全错误的。您应该知道,您不能为成员项(属性,字段等)创建相同的名称。它会混淆编译器。
我建议修改你的界面:
public interface IItemContainer
{
List<Item> ChosenItems { get; set; }
T ChosenItem<T>() where T : Item;
}
现在在您的实施中:
public class ItemContainer : IItemContainer
{
IItemContainer.ChosenItems
{
get { // your implementation
}
set { // your implementation
}
}
T IItemContainer.ChosenItem<T>()
{
return ((IItemContainer)this).ChosenItems.OfType<T>().FirstOrDefault();
}
}
此方法可让您存储源自Item
的不同对象,并使用ChosenItem<T>()
方法返回所需的对象。
修改强>
我有另一个操作项目列表的界面,因为某些子模块只能在一个项目上运行,而一些子模块只在一个项目上运行。我还需要独立存储每个实现类型的实例。
您可以随时使用工厂集合之类的东西(不知道名称是否正确)。
public class ChosenItemCollection
{
Dictionary<Type, Item> _fac = new Dictionary<Type, Item>();
public T Add<T>(T item) where T : Item
{
if(!_fac.ContainsKey(typeof(T))
{
_fac.Add(typeof(T), item);
}
else
{
_fac[typeof(T)] = item;
}
}
public T GetChosenItem<T>() where T : Item
{
if(_fac.ContainsKey(typeof(T))
return _fac[typeof(T)];
return null;
}
}
然后在您的界面而不是List<Item> ChosenItems
,您可以ChosenItemCollection ChosenItems
。
在你的例子中使用它:
GreedyItem item = // ...
ItemContainer.ChosenItems.Add(item);
ItemContainer.ChosenItem.ChosenItem<GreedyItem>();
答案 3 :(得分:1)
我认为Pidon
有一个很好的解决方案。但是在使用未实现的Item
派生时可能会导致运行时错误。
另一个解决方案可能是添加属性,这些属性将对已实现的类型执行转换:
public class ChosenItemsContainer : IItemContainer<FabulousItem>, IItemContainer<NiceItem>, IItemContainer<GreedyItem>
{
// these properties are only visible when casting to the correct
// interface. Which the public properties below will do.
FabulousItem IItemContainer<FabulousItem>.ChosenItem { get; set; }
GreedyItem IItemContainer<GreedyItem>.ChosenItem { get; set; }
NiceItem IItemContainer<NiceItem>.ChosenItem { get; set; }
// return this as IItemContainer<FabulousItem>
public IItemContainer<FabulousItem> AsFabulous
{
get
{
return (IItemContainer<FabulousItem>)this;
}
}
// return this as IItemContainer<NiceItem>
public IItemContainer<NiceItem> AsNice
{
get
{
return (IItemContainer<NiceItem>)this;
}
}
// return this as IItemContainer<GreedyItem>
public IItemContainer<GreedyItem> AsGreedy
{
get
{
return (IItemContainer<GreedyItem>)this;
}
}
}
ChosenItemsContainer container = new ChosenItemsContainer();
container.AsFabulous.ChosenItem = new FabulousItem();
container.AsNice.ChosenItem = new NiceItem();
container.AsGreedy.ChosenItem = new GreedyItem();
这种方式每个实现的类型都有自己的ChosenItem实例。我认为这是一个干净的解决方案,而不会在代码中混淆泛型<T>
。