首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >概论思维方式的概念问题

概论思维方式的概念问题
EN

Stack Overflow用户
提问于 2018-12-03 10:30:07
回答 3查看 75关注 0票数 0

我是一个普通的C#编码器,我在泛型方面有一些困难。当我按顺序学习这门课的时候,没有问题。但是当我看到内部样式中的泛型类或方法时,我遇到了一些概念理解问题。;

例如,如果我看到类似于List<string>的代码,我假设有一个list类,这意味着您可以使用string进行一些操作。这没有什么问题。但是,如果我看到一个像Catalog<Book>之类的类,我会怎么想?这是否意味着有一个Catalog类,而您只能使用book类进行操作?当我看到复杂的泛型时,我会怎么看待这些词呢?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-12-03 11:01:01

您提到List<string>的意思是“有一个list类,它意味着您可以使用string进行一些操作”。这是真的,但不是真的。List<T>意味着您可以对对象列表进行操作,其中T是对象类型的占位符。List<string>没有任何特定于字符串的功能,除了string是列表所包含的类型之外;List<T>类提供的所有操作都与字符串无关,而是与列表相关。

如果您有一个从List<string>派生的类,那么它可能具有特定于string的功能,因为在这种情况下,类定义显式地包括字符串类型。

代码语言:javascript
复制
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,它声明条目具有属性TitleCreator (例如,Book /Title的作者)、PublisherPublishDate等等。然后,Catalog<T>类将提供一种保存这些类型的多个项的方法,并将提供允许您搜索这些属性的方法。

还请注意,泛型不一定是集合;您可以有一个泛型类,它接受给定类型的单个实例,甚至可以是一个泛型类,它不包含任何“内部”值,而是只提供对该类型的操作。我们经常看到在依赖项注入中使用泛型的“单个实例”,其中泛型用于保存单个实例,例如:

代码语言:javascript
复制
builder.RegisterInstance(new SqlServerDatabase(myDefaultConnectionString))
   .As<IDatabase>()

也就是说,允许系统中任何具有功能的代码与IDatabase集成,以使用到SqlServerDatabase实例的连接;尽管仅通过将这一行代码(以及连接字符串的值)更改为下面的代码,我们可以将其转换为MySqlDatabase实例。

代码语言:javascript
复制
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。通过创建从该类派生的类,我们可以在特定类型的对象之间创建不同的比较,比如我们可能希望比较字符串的长度,而不是值(或者如果变得更加复杂/真实,可能是因为它们的拼字得分),例如:

代码语言:javascript
复制
class StringLengthComparer: IComparer<string>
{
    public int Compare(string x, string y)
    {
        return Math.Sign((x?.Length ?? 0).CompareTo(y?.Length ?? 0));
    }
}
票数 1
EN

Stack Overflow用户

发布于 2018-12-03 10:50:22

如果我们按字面意思命名,仿制药就更容易理解了。

具有或关于某一类别或一组事物的;不具体的。

我可以编写对某个对象执行操作的特定类,如下所示:

代码语言:javascript
复制
public class BookStorage
{
    private Book _item;

    public void StoreItem(Book item)
    {
        _item = item;
    }

    public Book RetrieveItem()
    {
        return _item;
    }
}

这是一个相当简单的类,但是如果我想处理其他事情(不仅仅是书籍),我最终会得到许多类似于这个类的类。

代码语言:javascript
复制
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;
    }
}

事实上,我的类并不关心项目是图书还是字符串,因为它不依赖于Bookstring的任何成员。

因此,如果我们使类更通用(不那么具体),我们可以允许使用者稍后提供类型参数。我们通常称未知类型为T,但这只是一种约定。

现在我们有了一个泛型存储类,它将在以后指定T类型。它与使用者相同,并得到与它是特定类时相同的类型检查,也就是说,如果我创建new Storage<Book>(),它的行为将与BookStorage类一样。但是,我现在可以创建新的存储类型,而无需添加更多的类,例如new Storage<string>()new Storage<Customer>()

代码语言:javascript
复制
public class Storage<T>
{
    private T _item;

    public void StoreItem(T item)
    {
        _item = item;
    }

    public T RetrieveItem()
    {
        return _item;
    }
}

我还可以将其提升到更高的水平,并说我将依赖于我的泛型类中的某些行为。例如,如果我只想存储有效的项,我可以向T添加一个约束,说明它必须实现IValidatable接口。这意味着我不能再创建一个new Storage<string>(),因为它不满足约束--但是只要BookCustomerBuilding满足约束,我就可以将它用于所有这些。

代码语言:javascript
复制
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;
    }
}

总之,泛型使您的类不那么紧密地绑定到它所操作的类型,从而允许使用者为不同的类型重用该类。

票数 4
EN

Stack Overflow用户

发布于 2018-12-03 11:07:19

例如,如果我看到类似于List<string>的代码,我假设有一个list类,这意味着您可以使用string进行一些操作。

不对。如果您看到Foo<T>,那么FooT并不一定是classes。它们也可以是interfaceSystem.Collections.Generic.IEnumerable<T>是泛型interface的一个例子。List实现了这个interface。当您看到Foo<T>时,您唯一知道的是,Foo是某种概念,或者是class,或者是interface,它正在使用T做一些事情。在您的Catalog<Book>示例中,Catalog要么是class,要么是interface,并且正在使用Book进行操作。既然这里的名字是自己说的,我们就可以推断出我们有一本书目录。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53591856

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档