简体   繁体   English

在 C# 中指定泛型类型参数时如何使用`dynamic`?

[英]How to use the `dynamic` when specifying generic type arguments in C#?

How to use the dynamic when specifying generic type arguments in C#?在 C# 中指定泛型类型参数时如何使用dynamic

I am reading the CLR via C# book.我正在通过 C#书籍阅读CLR And I come across the following paragraph:我遇到了以下段落:

It is also possible to use dynamic when specifying generic type arguments to a generic class (reference type), a structure (value type), an interface, a delegate, or a method.在为泛型类(引用类型)、结构(值类型)、接口、委托或方法指定泛型类型参数时,也可以使用动态。 When you do this, the compiler converts dynamic to Object and applies DynamicAttribute to the various pieces of metadata where it makes sense.执行此操作时,编译器会将动态转换为对象,并将 DynamicAttribute 应用于有意义的各种元数据。 Note that the generic code that you are using has already been compiled and will consider the type to be Object;请注意,您正在使用的通用代码已经过编译,并且会将类型视为 Object; no dynamic dispatch will be performed because the compiler did not produce any payload code in the generic code.不会执行动态分派,因为编译器没有在通用代码中生成任何有效负载代码。

As far as I understand this excerpt tells that I can use the dynamic as a type argument in (eg) a class definition.据我了解,这段摘录告诉我可以在(例如)类定义中使用dynamic作为类型参数。 But after trying this out I come to a conclusion that it is no different from using any other placeholder in the type argument.但是在尝试了这个之后,我得出一个结论,它与在类型参数中使用任何其他占位符没有什么不同。 So, I doubt that my understanding is correct.所以,我怀疑我的理解是正确的。

using System;

namespace myprogram
{
    class A<dynamic> {
        public dynamic a;
    }

    class B {
        public Int32 b;
    }

    class C<T> {
        public T c;
    }

    class Program {
        static void Main(string[] args) {
            //Cannot implicitly convert type 'string' to 'myprogram.B' [Console.NET]csharp(CS0029)
            //A<B> a = new A<B> {a = "foo"};

            //Cannot implicitly convert type 'string' to 'myprogram.B' [Console.NET]csharp(CS0029)
            //C<B> c = new C<B> {c = "foo"};

            //as you can see it does not matter if I use the T or dynamic, the effect is the same
            //so, what is the use of using the dynamic in the class definition?
        }
    }
}

It is very important to understand the difference between type "arguments" and type "parameters".理解类型“参数”和类型“参数”之间的区别非常重要。

Consider this:考虑一下:

class Foo<T> { } // "T" is a type parameter

...

Foo<int> f; // "int" is a type argument

Type parameters declare what types you can pass to this generic type/method.类型参数声明可以传递给这个泛型类型/方法的类型。 Type parameters are essentially identifiers, not an existing type.类型参数本质上是标识符,而不是现有类型。 When you pass a type to a generic type/method, the type you passed is called the type argument.当您将类型传递给泛型类型/方法时,您传递的类型称为类型参数。 This is quite similar to the difference between a method parameter and argument .这与方法参数和实参之间的区别非常相似。

So the excerpt is trying to say that given a generic type, you can pass the type dynamic to it, and it will be treated as object by the CLR.所以摘录试图说给定一个泛型类型,你可以将类型dynamic传递给它,它会被 CLR 视为object It doesn't mean that you can do this:这并不意味着您可以这样做:

class A<dynamic> {

}

It means that you can do this:这意味着你可以这样做:

var list = new List<dynamic>();

Or with the types declared in your code:或者使用代码中声明的类型:

C<dynamic> c = new C<dynamic> {c = "foo"};

Short answer: in your code dynamic is just a type parameter name, you're not actually passing an argument.简短回答:在您的代码中, dynamic只是一个类型参数名称,您实际上并没有传递参数。

As far as I understand this excerpt tells that I can use the dynamic as a type argument in (eg) a class definition.据我了解,这段摘录告诉我可以在(例如)类定义中使用 dynamic 作为类型参数。

There are no type arguments in a class definition.类定义中没有类型参数 In the definition of a generic type there are type parameters .在泛型类型的定义中有类型参数 When you construct a generic type these are type arguments.当您构造泛型类型时,这些是类型参数。 So this:所以这:

class A<dynamic>
{
}

var a = new A<string>();

is a generic type with one type parameter whose name is dynamic .是具有一个名称为dynamic类型参数的泛型类型。 Then follows an instantiation of the type where string is passed as a type argument to the type parameter dynamic .然后是类型的实例化,其中string作为类型参数传递给类型参数dynamic This:这个:

class A<T>
{
}

var a = new A<dynamic>();

is a generic type with one type parameter whose name is T .是具有一个名称为T类型参数的泛型类型。 Then follows an instantiation of the type where dynamic is passed as a type argument to the type parameter T .然后是类型的实例化,其中dynamic作为类型参数传递给类型参数T

You're looking for the latter, not the former.您正在寻找后者,而不是前者。

You can use dynamic as an Argument, so you can use您可以使用动态作为参数,因此您可以使用

var c = new C<dynamic>();

But you cannot use a concrete Type, to build a generic Type, like但是您不能使用具体类型来构建通用类型,例如

     class A<dynamic> { }
     class B<int> { }

In underline: This you should NOT do !下划线:你不应该这样做! You are defining an argument name here !您正在此处定义参数名称!

Actually it doesn't cause compile-error, but the word "int" as treated as a parameter name, same as there would be T. It's a good paradigm to use names starting with T for generic type parameters, not to mix it up, with any type from the Rest of your program.实际上它不会导致编译错误,但是“int”一词被视为参数名称,与 T 相同。使用以 T 开头的名称作为泛型类型参数是一个很好的范例,而不是将其混淆,使用程序其余部分中的任何类型。

As you concluded yourself, your definition of A and C are completly identical, except you are confused, cause the word dynamic has nothing to do with the type dynamic in this place.正如您自己总结的那样,您对 A 和 C 的定义完全相同,只是您感到困惑,因为这里的动态一词与类型 dynamic 无关。

If you want to assign a string, of course you have to create a new C<string>() or new C<object>() or any other type accepting a string.如果要分配字符串,当然必须创建一个new C<string>()new C<object>()或任何其他接受字符串的类型。

In my case I was in reality masking an ExpandoObject as a dynamic, so I ended up using code like this:在我的例子中,我实际上是将 ExpandoObject 屏蔽为动态的,所以我最终使用了这样的代码:

static async Task<TReturn> GenericMethodAsync<TReturn()
{
    if (typeof(TReturn) == typeof(ExpandoObject))
        // Return an ExpandoObject
}

Which was then used by a method like this one然后被这样的方法使用

static async Task<dynamic> OtherMethodAsync()
{
    return await GenericMethodAsync<ExpandoObject>();
}

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

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