简体   繁体   English

在方法签名中使用 generics 有什么优势?

[英]What are the advantages of using generics in method signatures?

(Thanks everyone for the answers, here is my refactored example , in turn another StackOverflow question about the Single Responsibility Principle.) (谢谢大家的回答, 这是我重构的例子,又是关于单一职责原则的另一个 StackOverflow 问题。)

Coming from PHP to C#, this syntax was intimidating:从 PHP 到 C#,这种语法令人生畏:

container.RegisterType<Customer>("customer1");

until I realized it expresses the same thing as:直到我意识到它表达的意思是一样的:

container.RegisterType(typeof(Customer), "customer1");

as I demonstrate in the code below.正如我在下面的代码中演示的那样。

So is there some reason why generics is used here (eg throughout Unity and most C# IoC containers) other than it just being a cleaner syntax, ie you don't need the typeof() when sending the type?那么这里使用 generics 有什么原因(例如整个 Unity 和大多数 C# IoC 容器),除了它只是一种更简洁的语法,即发送类型时不需要 typeof() ?

using System;

namespace TestGenericParameter
{
    class Program
    {
        static void Main(string[] args)
        {
            Container container = new Container();
            container.RegisterType<Customer>("test");
            container.RegisterType(typeof(Customer), "test");

            Console.ReadLine();
        }
    }

    public class Container
    {
        public void RegisterType<T>(string dummy)
        {
            Console.WriteLine("Type={0}, dummy={1}, name of class={2}", typeof(T), dummy, typeof(T).Name);
        }

        public void RegisterType(Type T, string dummy)
        {
            Console.WriteLine("Type={0}, dummy={1}, name of class={2}", T, dummy, T.Name);
        }

    }

    public class Customer {}
}

//OUTPUT:
//Type=TestGenericParameter.Customer, dummy=test, name of class=Customer
//Type=TestGenericParameter.Customer, dummy=test, name of class=Customer

A primary reason is the type safety at compile time.一个主要原因是编译时的类型安全。 If you are passing two Type objects you are placing the responsibility at the developer instead of the compiler.如果您传递两个Type对象,则您将责任放在开发人员而不是编译器身上。

This is also why many IoC containers utilizes it, as your compiler will complain if an concrete type isn't inheriting the abstract type.这也是许多 IoC 容器使用它的原因,因为如果具体类型没有继承抽象类型,您的编译器会报错。

public void Register<TAbstract, TConcrete>() where TConcrete : TAbstract
{
}

This code will only work if TConcrete is implementing or inheriting TAbstract .此代码仅在TConcrete实现或继承TAbstract If this method took two Type parameters, your method should validate this relationship.如果此方法采用两个Type参数,则您的方法应验证此关系。

One reason when generics are very useful is when the generic type parameter is used as the type of a parameter or as the return type of the method. generics 非常有用的一个原因是泛型类型参数用作参数的类型或方法的返回类型。 That means, you can write methods like这意味着,您可以编写类似的方法

public T GetAs<T>(string name)

where the return type can be checked by the compiler and boxing value types can sometimes be avoided.编译器可以检查返回类型,有时可以避免装箱值类型。 The caller would write:调用者会写:

int value = GetAs<int>("foo");

Whithout generics, you would have to write如果没有 generics,您将不得不写

public object GetAs(Type t, string name)

and the caller has to cast the result again:并且调用者必须再次转换结果:

int value = (int)GetAs(typeof(int), "foo");

A simple answer is type inference where possible.一个简单的答案是尽可能进行类型推断

If the generic type is used in the method signature, you can omit it because the type could be inferred:如果在方法签名中使用了泛型类型,则可以省略它,因为可以推断出类型:

void SomeMethod<T>(T x, T y) where T : IComparable<T> {
    Console.WriteLine("Result: {0} to {1} is {2}", x, y, x.CompareTo(y));
}

So the usage is simplified:所以简化了用法:

SomeMethod(3, 4);         // instead of SomeMethod<int>(3, 4);
SomeMethod("one", "two"); // instead of SomeMethod<string>("one", "two");

If the generic type parameter is not used in the method signature the type inference is not possible:如果方法签名中未使用泛型类型参数,则无法进行类型推断:

var emptySequence = Enumerable.Empty<int>();

For one example, compare the code needed to create an instance of your type using the typeof option versus a generic.例如,比较使用typeof选项和泛型创建类型实例所需的代码。 Or return an instance of the type.或者返回该类型的一个实例。 Or accept an instance of the type as an argument.或者接受该类型的一个实例作为参数。 Or set a property on an instance of the type.或者在该类型的实例上设置一个属性。

In general, if you will be working only with the type itself you can accept a type parameter.通常,如果您只使用类型本身,则可以接受类型参数。 If you want to do anything with an instance of the type, use a generic.如果您想对该类型的实例执行任何操作,请使用泛型。

Another reason to use a generic is if you want to apply constraints to the type.使用泛型的另一个原因是如果您想对类型应用约束。 For example, you can require the type to implement one or several interfaces, inherit another type, be a reference type or value type, have a default constructor, or some combination of the above.例如,您可以要求该类型实现一个或多个接口、继承另一种类型、作为引用类型或值类型、具有默认构造函数或以上的某种组合。 The compiler will enforce this so you can't build code that doesn't comply with your requirements.编译器将强制执行此操作,因此您无法构建不符合您要求的代码。

I think one of the primary uses is type safety with arguments and return values.我认为主要用途之一是使用 arguments 和返回值进行类型安全。 In your example case, there is not much use for generics, because the input/output types (string) do not match the generic case (customers).在您的示例案例中,generics 没有太多用处,因为输入/输出类型(字符串)与通用案例(客户)不匹配。

A more appropriate use might be:更合适的用法可能是:

public T RegisterType<T>(string name) 
{
    T obj = new T();
    obj.DoSomething();
    return obj;
}

or maybe或者可能

public void DoSomething<T>(T obj) 
{
    //operate on obj
}

If you didn't use Generics, you'd either have to overload a method for each type you want to support, or you'd have to accept the parameter as an object and perform casting logic.如果您没有使用 Generics,则必须为要支持的每种类型重载方法,或者必须将参数作为 object 接受并执行转换逻辑。

I'd say the best reason is type safety, using the "where" keyword, to ensure that the generic type is of a certain type (or sub-class/implementor).我想说最好的理由是类型安全,使用“where”关键字来确保泛型类型是某种类型(或子类/实现者)。 Using "typeof" will let you send anything through.使用“typeof”可以让你发送任何东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM