在 C# 中指定泛型类型参数时如何使用"动态"?



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

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

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

据我了解,这段摘录告诉我,我可以将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只是一个类型参数名称,您实际上并没有传递参数。

据我了解,这段摘录告诉我,我可以将动态用作(例如(类定义中的类型参数。

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

class A<dynamic>
{
}
var a = new A<string>();

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

class A<T>
{
}
var a = new A<dynamic>();

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

你在寻找的是后者,而不是前者。

您可以将 dynamic 用作参数,因此您可以使用

var c = new C<dynamic>();

但是你不能使用具体的类型来构建一个泛型类型,比如

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

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

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

正如你自己总结的那样,你对 A 和 C 的定义是完全相同的, 除了你很困惑,因为动态这个词与类型无关 这个地方动态。

如果要分配字符串,当然必须创建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>();
}

最新更新