Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#泛型:简化类型签名_C#_Generics - Fatal编程技术网

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参数。那么这是不可能的。