name of class with generic parameters? - c#

I'm trying to generate code for series of generic classes using T4.
I want to know how to get full class name using reflection?
public class Foo<TFirst, TSecond> {}
var type = typeof(Foo<,>);
var name = type.FullName; // returns "Foo`2"
what I want is full name with actual generic parameter names that I've written
"Foo<TFirst, TSecond>"
Note that they are not known type, as I said I'm generating code using T4, so I want to have exact naming to use it for code generations, as an example, inside generic methods.
I tried this answers but they require to pass known type which is not what I want.

You can access the type parameter names by reflection using Type.GetGenericArguments:
using System;
public class Foo<TFirst, TSecond> {}
class Test
{
static void Main()
{
var type = typeof(Foo<,>);
Console.WriteLine($"Full name: {type.FullName}");
Console.WriteLine("Type argument names:");
foreach (var arg in type.GetGenericArguments())
{
Console.WriteLine($" {arg.Name}");
}
}
}
Note that that's giving the type parameter names because you've used the generic type definition; if you used var type = typeof(Foo<string, int>); you'd get String and Int32 listed (as well as a longer type.FullName.)
I haven't written any T4 myself, so I don't know whether this is any use to you - in order to get to Foo<TFirst, TSecond> you'd need to write a bit of string manipulation logic. However, this is the only way I know of to get at the type arguments/parameters.

Related

What is the actual type of JSON like object in C# (new {};)

I was learning C# and found that there is some type of value defined by
var json = new {name="App", age=20};
Although this seems to be similar to the JSON type. But when I tried to use the GetType method, I got <>f__AnonymousType0`2[System.String,System.Int32]
Can anyone help me in this please?
In case you want the full code
using System;
public class Program
{
public static void Main()
{
var c = new { name="App", age=22 };
Console.WriteLine(c.GetType());
Console.WriteLine(c);;
}
}
It's called Anonymous Type and it has no relation to JSON.
You can read about it FROM MSDN
Anonymous types provide a convenient way to encapsulate a set of
read-only properties into a single object without having to explicitly
define a type first. The type name is generated by the compiler and is
not available at the source code level. The type of each property is
inferred by the compiler.

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

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?
}
}
}
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"};
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.
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.
In my case I was in reality masking an ExpandoObject as a dynamic, so I ended up using code like this:
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>();
}

Determining if a field is using a generic parameter

I've been baffled by this and can't seem to get my head around it so hopefully someone can point me in the right direction.
I have a class as follows:
public class Foo<T>
{
public List<T> Data;
}
Now I'm writing code to reflect this class and want to work out a way of determining that the field Data has a generic parameter being used.
My initial approach was to continue going down as many levels as I could and once I hit the IsGenericParameter field set to true I would rather than reflect the type name instead place a "Generic Argument" string there, however I can't seem to get this to work the way I want it to.
I've looked around but every solution I've found seems to point to a dead end with this at the moment.
You want IsGenericType, not IsGenericParameter:
bool isGeneric = typeof(Foo<int>).GetField("Data").FieldType.IsGenericType;
If you want to know of the parameter for the List is generic, then you have to look one more level down:
bool isGeneric = typeof(Foo<>).GetField("Data")
.FieldType
.GetGenericArguments()[0] // only generic argument to List<T>
.IsGenericParameter;
what if Data field was a Dictionary with Dictionary<string, T>. How would I determine which type was using a generic parameter?
Call GetGenericArguments on the type and look at each type in the resulting array
public class Foo<T>
{
public Dictionary<string, T> Bar;
}
Type[] types = typeof(Foo<>).GetField("Bar").FieldType.GetGenericArguments();
Console.WriteLine("{0}\n{1}",
types[0].IsGenericParameter, // false, type is string
types[1].IsGenericParameter // true, type is T
);
Basically, IsGenericParameter is used when looking at the generic parameters of a type to see if it is generic or if is has a type sepcified.
Here is how to distinguish generic types that rely on class type parameter from generic types that do not. Consider this example:
class Foo<T> {
public List<T> field1; // You want this field
public List<int> field2; // not this field
}
Start by getting generic type definition, and pulling its type arguments:
var g = typeof(Foo<string>).GetGenericTypeDefinition();
var a = g.GetGenericArguments();
This will give you an array with a single type that represents generic type parameter T. Now you can go through all fields, and search for that type among generic type arguments of field types, like this:
foreach (var f in g.GetFields()) {
var ft = f.FieldType;
if (!ft.IsGenericType) continue;
var da = ft.GetGenericArguments();
if (da.Any(xt => a.Contains(xt))) {
Console.WriteLine("Field {0} uses generic type parameter", f.Name);
} else {
Console.WriteLine("Field {0} does not use generic type parameter", f.Name);
}
}
This code produces the following output:
Field field1 uses generic type parameter
Field field2 does not use generic type parameter

Create an instance of C# generic class [duplicate]

The title is kind of obscure. What I want to know is if this is possible:
string typeName = <read type name from somwhere>;
Type myType = Type.GetType(typeName);
MyGenericClass<myType> myGenericClass = new MyGenericClass<myType>();
Obviously, MyGenericClass is described as:
public class MyGenericClass<T>
Right now, the compiler complains that 'The type or namespace 'myType' could not be found." There has got to be a way to do this.
You can't do this without reflection. However, you can do it with reflection. Here's a complete example:
using System;
using System.Reflection;
public class Generic<T>
{
public Generic()
{
Console.WriteLine("T={0}", typeof(T));
}
}
class Test
{
static void Main()
{
string typeName = "System.String";
Type typeArgument = Type.GetType(typeName);
Type genericClass = typeof(Generic<>);
// MakeGenericType is badly named
Type constructedClass = genericClass.MakeGenericType(typeArgument);
object created = Activator.CreateInstance(constructedClass);
}
}
Note: if your generic class accepts multiple types, you must include the commas when you omit the type names, for example:
Type genericClass = typeof(IReadOnlyDictionary<,>);
Type constructedClass = genericClass.MakeGenericType(typeArgument1, typeArgument2);
Unfortunately no there is not. Generic arguments must be resolvable at Compile time as either 1) a valid type or 2) another generic parameter. There is no way to create generic instances based on runtime values without the big hammer of using reflection.
Some additional how to run with scissors code. Suppose you have a class similar to
public class Encoder() {
public void Markdown(IEnumerable<FooContent> contents) { do magic }
public void Markdown(IEnumerable<BarContent> contents) { do magic2 }
}
Suppose at runtime you have a FooContent
If you were able to bind at compile time you would want
var fooContents = new List<FooContent>(fooContent)
new Encoder().Markdown(fooContents)
However you cannot do this at runtime. To do this at runtime you would do along the lines of:
var listType = typeof(List<>).MakeGenericType(myType);
var dynamicList = Activator.CreateInstance(listType);
((IList)dynamicList).Add(fooContent);
To dynamically invoke Markdown(IEnumerable<FooContent> contents)
new Encoder().Markdown( (dynamic) dynamicList)
Note the usage of dynamic in the method call. At runtime dynamicList will be List<FooContent> (additionally also being IEnumerable<FooContent>) since even usage of dynamic is still rooted to a strongly typed language the run time binder will select the appropriate Markdown method. If there is no exact type matches, it will look for an object parameter method and if neither match a runtime binder exception will be raised alerting that no method matches.
The obvious draw back to this approach is a huge loss of type safety at compile time. Nevertheless code along these lines will let you operate in a very dynamic sense that at runtime is still fully typed as you expect it to be.
My requirements were slightly different, but will hopefully help someone. I needed to read type from a config and instantiate the generic type dynamically.
namespace GenericTest
{
public class Item
{
}
}
namespace GenericTest
{
public class GenericClass<T>
{
}
}
Finally, here is how you call it. Define the type with a backtick.
var t = Type.GetType("GenericTest.GenericClass`1[[GenericTest.Item, GenericTest]], GenericTest");
var a = Activator.CreateInstance(t);
If you know what types will be passed you can do this without reflection. A switch statement would work. Obviously, this would only work in a limited number of cases, but it'll be much faster than reflection.
public class Type1 { }
public class Type2 { }
public class Generic<T> { }
public class Program
{
public static void Main()
{
var typeName = nameof(Type1);
switch (typeName)
{
case nameof(Type1):
var type1 = new Generic<Type1>();
// do something
break;
case nameof(Type2):
var type2 = new Generic<Type2>();
// do something
break;
}
}
}
In this snippet I want to show how to create and use a dynamically created list. For example, I'm adding to the dynamic list here.
void AddValue<T>(object targetList, T valueToAdd)
{
var addMethod = targetList.GetType().GetMethod("Add");
addMethod.Invoke(targetList, new[] { valueToAdd } as object[]);
}
var listType = typeof(List<>).MakeGenericType(new[] { dynamicType }); // dynamicType is the type you want
var list = Activator.CreateInstance(listType);
AddValue(list, 5);
Similarly you can invoke any other method on the list.

Dynamically create an object of <Type>

I have a table in my database that I use to manage relationships across my application. it's pretty basic in it's nature - parentType,parentId, childType, childId... all as ints. I've done this setup before, but I did it with a switch/case setup when I had 6 different tables I was trying to link. Now I have 30 tables that I'm trying to do this with and I would like to be able to do this without having to write 30 case entries in my switch command.
Is there a way that I can make reference to a .Net class using a string? I know this isn't valid (because I've tried several variations of this):
Type t = Type.GetType("WebCore.Models.Page");
object page = new t();
I know how to get the Type of an object, but how do I use that on the fly to create a new object?
This link should help:
https://learn.microsoft.com/en-us/dotnet/api/system.activator.createinstance
Activator.CreateInstance will create an instance of the specified type.
You could wrap that in a generic method like this:
public T GetInstance<T>(string type)
{
return (T)Activator.CreateInstance(Type.GetType(type));
}
If the type is known by the caller, there's a better, faster way than using Activator.CreateInstance: you can instead use a generic constraint on the method that specifies it has a default parameterless constructor.
Doing it this way is type-safe and doesn't require reflection.
T CreateType<T>() where T : new()
{
return new T();
}
public static T GetInstance<T>(params object[] args)
{
return (T)Activator.CreateInstance(typeof(T), args);
}
I would use Activator.CreateInstance() instead of casting, as the Activator has a constructor for generics.
You want to use Activator.CreateInstance.
Here is an example of how it works:
using System;
using System.Runtime.Remoting;
class Program
{
static void Main()
{
ObjectHandle o = Activator.CreateInstance("mscorlib.dll", "System.Int32");
Int32 i = (Int32)o.Unwrap();
}
}
Assuming you have the following type:
public class Counter<T>
{
public T Value { get; set; }
}
and have the assembly qualified name of the type, you can construct it in the following manner:
string typeName = typeof(Counter<>).AssemblyQualifiedName;
Type t = Type.GetType(typeName);
Counter<int> counter =
(Counter<int>)Activator.CreateInstance(
t.MakeGenericType(typeof(int)));
counter.Value++;
Console.WriteLine(counter.Value);
Here is a function I wrote that clones a record of type T, using reflection.
This is a very simple implementation, I did not handle complex types etc.
public static T Clone<T>(T original)
{
T newObject = (T)Activator.CreateInstance(original.GetType());
foreach (var prop in original.GetType().GetProperties())
{
prop.SetValue(newObject, prop.GetValue(original));
}
return newObject;
}
I hope this can help someone.
Assaf

Categories