任何人都可以举一个很好的例子来说明如何使用泛型类?

Iri*_*son 14 c# generics class

我们最近了解了C#中的泛型类,但我们的老师没有提到它们可以用于什么.我真的找不到任何好的例子,如果有人帮助我,我会非常高兴:)

你有自己的通用课程吗?你用它做了什么?

一些代码示例会让我和我的同学们真的很开心!请原谅,英语不好,我来自瑞典:)

快乐的编程!

对不起 - 我想我可以把问题写得好一点.我熟悉通用集合.我只是想知道你自己的泛型类可以用于什么.

并且感谢您的MSDN链接,我在发布问题之前就已经阅读了它们,但也许我错过了什么?我会再看看!

Cha*_*lie 10

通用集合

集合的泛型非常有用,因为它们允许编译时类型安全.这有用的原因有以下几点:

  • 在检索值时不需要铸造.这不仅具有性能优势,还消除了运行时出现转换异常的风险

  • 将值类型添加到非泛型列表(如ArrayList)时,必须将值设置为框.这意味着它们存储为引用类型.这也意味着不仅值被存储在内存中,而且对它的引用也是如此,因此使用了比necessery更多的内存.使用通用列表时,可以消除此问题.

通用类

通用类可用于重用不同类型的公共代码.以一个简单的非通用工厂类为例:

public class CatFactory
{
  public Cat CreateCat()
  {
    return new Cat();
  }
}
Run Code Online (Sandbox Code Playgroud)

我可以使用泛型类为(几乎)任何类型提供工厂:

public class Factory<T> where T : new()
{
  public T Create()
  {
    return new T();
  }
}
Run Code Online (Sandbox Code Playgroud)

在这个例子中,我在类型参数T上放置了new()的泛型类型约束.这要求泛型类型包含一个无参数的构造函数,这使我能够在不知道类型的情况下创建实例.


x0n*_*x0n 6

只是因为你说你是瑞典人,我想我会举一个整合宜家家具的例子.你的套装沙发是北美的一种感染,所以我想我会回馈一些东西:)想象一个代表一个特殊的椅子和桌子套件的课程.为了保持真实,我甚至会使用无意义的瑞典语言同音异义词:

// interface for included tools to build your furniture
public interface IToolKit {
    string[] GetTools();
}

// interface for included parts for your furniture    
public interface IParts {
    string[] GetParts();
}

// represents a generic base class for IKEA furniture kit
public abstract class IkeaKit<TContents> where TContents : IToolKit, IParts, new() {
    public abstract string Title {
        get;
    }

    public abstract string Colour {
        get;
    }

    public void GetInventory() {
        // generic constraint new() lets me do this
        var contents = new TContents();
        foreach (string tool in contents.GetTools()) {
            Console.WriteLine("Tool: {0}", tool);
        }
        foreach (string part in contents.GetParts()) {
            Console.WriteLine("Part: {0}", part);
        }
    }
}

// describes a chair
public class Chair : IToolKit, IParts {
    public string[] GetTools() {
        return new string[] { "Screwdriver", "Allen Key" };
    }

    public string[] GetParts() {
        return new string[] {
            "leg", "leg", "leg", "seat", "back", "bag of screws" };
    }
}

// describes a chair kit call "Fnood" which is cyan in colour.
public class Fnood : IkeaKit<Chair> {
    public override string Title {
        get { return "Fnood"; }
    }

    public override string Colour {
        get { return "Cyan"; }
    }
}

public class Snoolma : IkeaKit<Chair> {
    public override string Title {
        get { return "Snoolma "; }
    }

    public override string Colour {
        get { return "Orange"; }
    }
}
Run Code Online (Sandbox Code Playgroud)

好的,现在我们已经掌握了如何构建一些廉价家具所需的所有东西:

var fnood = new Fnood();
fnood.GetInventory(); // print out tools and components for a fnood chair!
Run Code Online (Sandbox Code Playgroud)

(是的,缺乏说明和椅子套件中的三条腿是故意的.)

希望这有助于以一种厚颜无耻的方式.


sup*_*cat 4

如果有一个 List 对象(非泛型),则可以将任何可以转换为 Object 的内容存储到其中,但无法在编译时知道从中得到什么类型的内容。相比之下,如果有一个泛型 List<Animal>,则可以存储到其中的唯一内容是 Animal 或其派生类,并且编译器可以知道从中提取的唯一内容将是 Animal。因此,编译器可以允许将内容从 List 中取出并直接存储到 Animal 类型的字段中,而不需要运行时类型检查。

此外,如果泛型类的泛型类型参数恰好是值类型,则使用泛型类型可以消除在 Object 之间进行转换的需要,这一过程称为“装箱”,它将值类型实体转换为引用类型对象; 装箱有点慢,有时会改变值类型对象的语义,因此最好尽可能避免。

请注意,尽管 SomeDerivedClass 类型的对象可以替代 TheBaseClass,但一般来说,GenericSomething<SomeDerivedClass> 不能替代 GenericSomething<TheBaseClass>。问题是,如果可以用 List<Giraffe> 替换 List<Zebra>,则可以将 List<Zebra> 传递给期望获取 List<Giraffe> 并在其中存储大象的例程。不过,有几种情况是允许可替代性的:

  1. 派生类型的数组可以传递给需要基类型数组的例程,前提是这些例程不会尝试将任何不属于正确派生类型的项存储到这些数组中。
  2. 如果这些接口唯一要做的就是返回(“输出”)该类型的值,则可以将接口声明为具有“输出”类型参数。长颈鹿供应商可以替代动物供应商,因为它要做的就是供应长颈鹿,而长颈鹿又可以替代动物。这样的接口对于那些参数是“协变的”。

此外,如果接口所做的唯一事情就是按值接受该类型的参数,则可以声明接口来声明“in”类型参数。食动物者可以用食长颈鹿者来代替,因为它能够吃掉所有动物,因此也能够吃掉所有长颈鹿。这样的接口对于那些参数是“逆变的”。