繁体   English   中英

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

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

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

我正在通过 C#书籍阅读CLR 我遇到了以下段落:

在为泛型类(引用类型)、结构(值类型)、接口、委托或方法指定泛型类型参数时,也可以使用动态。 执行此操作时,编译器会将动态转换为对象,并将 DynamicAttribute 应用于有意义的各种元数据。 请注意,您正在使用的通用代码已经过编译,并且会将类型视为 Object; 不会执行动态分派,因为编译器没有在通用代码中生成任何有效负载代码。

据我了解,这段摘录告诉我可以在(例如)类定义中使用dynamic作为类型参数。 但是在尝试了这个之后,我得出一个结论,它与在类型参数中使用任何其他占位符没有什么不同。 所以,我怀疑我的理解是正确的。

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?
        }
    }
}

理解类型“参数”和类型“参数”之间的区别非常重要。

考虑一下:

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

...

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

类型参数声明可以传递给这个泛型类型/方法的类型。 类型参数本质上是标识符,而不是现有类型。 当您将类型传递给泛型类型/方法时,您传递的类型称为类型参数。 这与方法参数和实参之间的区别非常相似。

所以摘录试图说给定一个泛型类型,你可以将类型dynamic传递给它,它会被 CLR 视为object 这并不意味着您可以这样做:

class A<dynamic> {

}

这意味着你可以这样做:

var list = new List<dynamic>();

或者使用代码中声明的类型:

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

简短回答:在您的代码中, dynamic只是一个类型参数名称,您实际上并没有传递参数。

据我了解,这段摘录告诉我可以在(例如)类定义中使用 dynamic 作为类型参数。

类定义中没有类型参数 在泛型类型的定义中有类型参数 当您构造泛型类型时,这些是类型参数。 所以这:

class A<dynamic>
{
}

var a = new A<string>();

是具有一个名称为dynamic类型参数的泛型类型。 然后是类型的实例化,其中string作为类型参数传递给类型参数dynamic 这个:

class A<T>
{
}

var a = new A<dynamic>();

是具有一个名称为T类型参数的泛型类型。 然后是类型的实例化,其中dynamic作为类型参数传递给类型参数T

您正在寻找后者,而不是前者。

您可以使用动态作为参数,因此您可以使用

var c = new C<dynamic>();

但是您不能使用具体类型来构建通用类型,例如

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

下划线:你不应该这样做! 您正在此处定义参数名称!

实际上它不会导致编译错误,但是“int”一词被视为参数名称,与 T 相同。使用以 T 开头的名称作为泛型类型参数是一个很好的范例,而不是将其混淆,使用程序其余部分中的任何类型。

正如您自己总结的那样,您对 A 和 C 的定义完全相同,只是您感到困惑,因为这里的动态一词与类型 dynamic 无关。

如果要分配字符串,当然必须创建一个new C<string>()new C<object>()或任何其他接受字符串的类型。

在我的例子中,我实际上是将 ExpandoObject 屏蔽为动态的,所以我最终使用了这样的代码:

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

然后被这样的方法使用

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

暂无
暂无

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

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