C#泛型:简化类型签名
如果我有一个如下所示的通用项类:C#泛型:简化类型签名,c#,generics,C#,Generics,如果我有一个如下所示的通用项类: abstract class Item<T> { } class Container<TItem, T> where TItem : Item<T> { } 抽象类项 { } 以及一个类似以下内容的物品容器: abstract class Item<T> { } class Container<TItem, T> where TItem : Item<T> { }
abstract class Item<T>
{
}
class Container<TItem, T>
where TItem : Item<T>
{
}
抽象类项
{
}
以及一个类似以下内容的物品容器:
abstract class Item<T>
{
}
class Container<TItem, T>
where TItem : Item<T>
{
}
类容器
其中:项目
{
}
既然TItem依赖于T,那么是否可以简化容器的类型签名,使其只接受一个类型参数?我真正想要的是这样的东西:
class Container<TItem>
where TItem : Item // this doesn't actually work, because Item takes a type parameter
{
}
类容器
其中TItem:Item//这实际上不起作用,因为Item接受一个类型参数
{
}
因此,我可以将其实例化如下:
class StringItem : Item<string>
{
}
var good = new Container<StringItem>();
var bad = new Container<StringItem, string>();
class-StringItem:Item
{
}
var good=新容器();
var bad=新容器();
当TItem是StringItem时,编译器应该能够推断出T是string,对吗?我该如何做到这一点
预期用途:
class MyItem : Item<string>
{
}
Container<MyItem> container = GetContainer();
MyItem item = container.GetItem(0);
item.MyMethod();
class MyItem:Item
{
}
Container=GetContainer();
MyItem=container.GetItem(0);
item.MyMethod();
我想这应该是你想要的。显然,您现在正在做的是Container
而不是Container
,但由于您没有包括使用示例,我看不出这是一个问题
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var myContainer = new Container<string>();
myContainer.MyItems = new List<Item<string>>();
}
}
public class Item<T> { }
public class Container<T>
{
// Just some property on your container to show you can use Item<T>
public List<Item<T>> MyItems { get; set; }
}
}
使用System.Collections.Generic;
命名空间控制台应用程序1
{
班级计划
{
静态void Main(字符串[]参数)
{
var myContainer=新容器();
myContainer.MyItems=新列表();
}
}
公共类项{}
公营货柜
{
//只是容器上的一些属性,显示您可以使用该项
公共列表MyItems{get;set;}
}
}
这个修订版怎么样
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var myContainer = new Container<StringItem>();
myContainer.StronglyTypedItem = new StringItem();
}
}
public class Item<T> { }
public class StringItem : Item<string> { }
// Probably a way to hide this, but can't figure it out now
// (needs to be public because it's a base type)
// Probably involves making a container (or 3rd class??)
// wrap a private container, not inherit it
public class PrivateContainer<TItem, T> where TItem : Item<T> { }
// Public interface
public class Container<T> : PrivateContainer<Item<T>, T>
{
// Just some property on your container to show you can use Item<T>
public T StronglyTypedItem { get; set; }
}
}
使用System.Collections.Generic;
命名空间控制台应用程序1
{
班级计划
{
静态void Main(字符串[]参数)
{
var myContainer=新容器();
myContainer.StronglyTypedItem=新StringItem();
}
}
公共类项{}
公共类StringItem:项{}
//也许是一种隐藏的方法,但现在还没弄明白
//(需要是公共的,因为它是基类型)
//可能涉及制作容器(或三等舱??)
//包装私有容器,而不是继承它
公共类PrivateContainer,其中TItem:Item{}
//公共接口
公营货柜:私家货柜
{
//只是容器上的一些属性,显示您可以使用该项
公共T StronglyTypedItem{get;set;}
}
}
我认为解决问题的一个可能方法是添加接口IItem
,代码结构如下所示
interface IItem { }
abstract class Item<T> : IItem { }
class Container<TItem> where TItem : IItem { }
class StringItem: Item<string> { }
接口IItem{}
抽象类项:IItem{}
类容器,其中TItem:IItem{}
类StringItem:项{}
现在您可以使用容器了
:
var container=newcontainer();
我想你可以。它的多态性。您可以重写抽象方法。在这种情况下,您可以将StringContainer类创建为类StringContainer,其中TItem:Item我不相信编译器可以部分推断泛型类型。抱歉,但这是不可能的…@DStanley:遗憾的是,我想您可能是对的。这可以编译,但我确实需要容器,而不是容器。@brianberns:为什么?(不是抱怨,只是对可能的答案有用)使用变得复杂,但想象一下容器上有一个名为GetItem(int index)的方法,它必须返回一个TItem,而不是Item。这允许调用者直接在结果上调用TItem方法,而不必将其从一个项转换到另一个项。@brianberns:请参阅我的edit@GeorgeDuckett:容器中的t
现在不是从项衍生而来吗?换句话说,列表
在示例中是一个列表
,而不是列表
。我认为,如果您将myContainer
声明为Container
的一个实例,这会起作用。这是一个很好的建议,但问题是Container确实需要知道TItem的底层T参数。那么这是不可能的。