1

How to use the dynamic when specifying generic type arguments in C#?

I am reading the CLR via C# book. 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. Note that the generic code that you are using has already been compiled and will consider the type to be 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 (e.g.) a class definition. 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?
        }
    }
}
qqqqqqq
  • 1,007
  • 7
  • 25
  • A `string` is not `A` or `C` and vice-versa. This is what the compiler is telling you and it's correct. – CodingYoshi Nov 24 '19 at 15:19
  • Read generics like this: `C` `C` is a class that has code which depends on anything that satisfies the interface of `B`. Now it's clear why you cannot do what you're trying because `string` does not satisfy the interface of `B`. – CodingYoshi Nov 24 '19 at 15:23

3 Answers3

1

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. 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"};
Sweeper
  • 145,870
  • 17
  • 129
  • 225
1

Short answer: in your code dynamic is just a type parameter name, you're not actually passing an argument.

As far as I understand this excerpt tells that I can use the dynamic as a type argument in (e.g.) a class definition.

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. Then follows an instantiation of the type where string is passed as a type argument to the type parameter dynamic. This:

class A<T>
{
}

var a = new A<dynamic>();

is a generic type with one type parameter whose name is T. Then follows an instantiation of the type where dynamic is passed as a type argument to the type parameter T.

You're looking for the latter, not the former.

V0ldek
  • 7,117
  • 17
  • 39
0

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.

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.

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.

Holger
  • 2,133
  • 1
  • 9
  • 13