我是一个普通的C#编码器,我在泛型方面有一些困难。当我按顺序学习这门课的时候,没有问题。但是当我看到内部样式中的泛型类或方法时,我遇到了一些概念理解问题。;
例如,如果我看到类似于List<string>的代码,我假设有一个list类,这意味着您可以使用string进行一些操作。这没有什么问题。但是,如果我看到一个像Catalog<Book>之类的类,我会怎么想?这是否意味着有一个Catalog类,而您只能使用book类进行操作?当我看到复杂的泛型时,我会怎么看待这些词呢?
发布于 2018-12-03 11:01:01
您提到List<string>的意思是“有一个list类,它意味着您可以使用string进行一些操作”。这是真的,但不是真的。List<T>意味着您可以对对象列表进行操作,其中T是对象类型的占位符。List<string>没有任何特定于字符串的功能,除了string是列表所包含的类型之外;List<T>类提供的所有操作都与字符串无关,而是与列表相关。
如果您有一个从List<string>派生的类,那么它可能具有特定于string的功能,因为在这种情况下,类定义显式地包括字符串类型。
void Main()
{
var demo = new StringList(){"one","two","three","four"};
Console.WriteLine(demo.MaxLength());
}
class StringList: List<string>
{
public int MaxLength()
{
return this.Max(s => s?.Length ?? 0); //handles nulls
}
}我们不能在MaxLength上使用List<T>函数,因为如果我们以int作为类型,这个方法就没有任何意义(即int没有Length属性)。但是,由于StringList是从List<string>派生的,所以我们有一个具体的类型,其中我们知道这个类型的所有项都有一个Length属性,所以有一个可以找到最大长度的方法是有意义的。
关于像Catalog<Book>这样的东西,名称(这是我们所要做的一切)将意味着存在一个类Catalog<T>,其中可能存在对T的一些限制,但是T满足了这些限制(例如,可能需要T实现一些接口,比如ICatalogItem,它声明条目具有属性Title、Creator (例如,Book /Title的作者)、Publisher、PublishDate等等。然后,Catalog<T>类将提供一种保存这些类型的多个项的方法,并将提供允许您搜索这些属性的方法。
还请注意,泛型不一定是集合;您可以有一个泛型类,它接受给定类型的单个实例,甚至可以是一个泛型类,它不包含任何“内部”值,而是只提供对该类型的操作。我们经常看到在依赖项注入中使用泛型的“单个实例”,其中泛型用于保存单个实例,例如:
builder.RegisterInstance(new SqlServerDatabase(myDefaultConnectionString))
.As<IDatabase>()也就是说,允许系统中任何具有功能的代码与IDatabase集成,以使用到SqlServerDatabase实例的连接;尽管仅通过将这一行代码(以及连接字符串的值)更改为下面的代码,我们可以将其转换为MySqlDatabase实例。
builder.RegisterInstance(new MySqlDatabase(myDefaultConnectionString))
.As<IDatabase>()我们没有任何实例的泛型示例是类似于IComparer<T>的例子,如本文所述:https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.icomparer-1?view=netframework-4.7.2。通过创建从该类派生的类,我们可以在特定类型的对象之间创建不同的比较,比如我们可能希望比较字符串的长度,而不是值(或者如果变得更加复杂/真实,可能是因为它们的拼字得分),例如:
class StringLengthComparer: IComparer<string>
{
public int Compare(string x, string y)
{
return Math.Sign((x?.Length ?? 0).CompareTo(y?.Length ?? 0));
}
}发布于 2018-12-03 10:50:22
如果我们按字面意思命名,仿制药就更容易理解了。
具有或关于某一类别或一组事物的;不具体的。
我可以编写对某个对象执行操作的特定类,如下所示:
public class BookStorage
{
private Book _item;
public void StoreItem(Book item)
{
_item = item;
}
public Book RetrieveItem()
{
return _item;
}
}这是一个相当简单的类,但是如果我想处理其他事情(不仅仅是书籍),我最终会得到许多类似于这个类的类。
public class BookStorage
{
private Book _item;
public void StoreItem(Book item)
{
_item = item;
}
public Book RetrieveItem()
{
return _item;
}
}
public class StringStorage
{
private string _item;
public void StoreItem(string item)
{
_item = item;
}
public string RetrieveItem()
{
return _item;
}
}事实上,我的类并不关心项目是图书还是字符串,因为它不依赖于Book或string的任何成员。
因此,如果我们使类更通用(不那么具体),我们可以允许使用者稍后提供类型参数。我们通常称未知类型为T,但这只是一种约定。
现在我们有了一个泛型存储类,它将在以后指定T类型。它与使用者相同,并得到与它是特定类时相同的类型检查,也就是说,如果我创建new Storage<Book>(),它的行为将与BookStorage类一样。但是,我现在可以创建新的存储类型,而无需添加更多的类,例如new Storage<string>()或new Storage<Customer>()。
public class Storage<T>
{
private T _item;
public void StoreItem(T item)
{
_item = item;
}
public T RetrieveItem()
{
return _item;
}
}我还可以将其提升到更高的水平,并说我将依赖于我的泛型类中的某些行为。例如,如果我只想存储有效的项,我可以向T添加一个约束,说明它必须实现IValidatable接口。这意味着我不能再创建一个new Storage<string>(),因为它不满足约束--但是只要Book、Customer或Building满足约束,我就可以将它用于所有这些。
public interface IValidatable
{
public bool IsValid();
}
public class Storage<T> where T : IValidatable
{
private T _item;
public void StoreItem(T item)
{
if (item.IsValid())
{
_item = item;
}
}
public T RetrieveItem()
{
return _item;
}
}总之,泛型使您的类不那么紧密地绑定到它所操作的类型,从而允许使用者为不同的类型重用该类。
发布于 2018-12-03 11:07:19
例如,如果我看到类似于
List<string>的代码,我假设有一个list类,这意味着您可以使用string进行一些操作。
不对。如果您看到Foo<T>,那么Foo和T并不一定是classes。它们也可以是interface。System.Collections.Generic.IEnumerable<T>是泛型interface的一个例子。List实现了这个interface。当您看到Foo<T>时,您唯一知道的是,Foo是某种概念,或者是class,或者是interface,它正在使用T做一些事情。在您的Catalog<Book>示例中,Catalog要么是class,要么是interface,并且正在使用Book进行操作。既然这里的名字是自己说的,我们就可以推断出我们有一本书目录。
https://stackoverflow.com/questions/53591856
复制相似问题