C# reflection generic property type - c#

Say that I have a class like this:
public class TestClass <T>
{
public T Prop { get; set; }
}
I'm trying to identify that the property type is T, not the actual type that is passed e.g. int
In order to clarify it a bit more:
TestClass<int> tc=new TestClass<int>();
tc.GetType().GetProperty("prop").PropertyType.Name; //this returns int, but I need "T"

When you create a TestClass<int> instance, you have a reified generic type - the property is int, not T.
To get at the actual generic type, you can use GetGenericTypeDefinition:
var genericType = tc.GetType().GetGenericTypeDefinition();
var typeName = genericType.GetProperty("Prop").PropertyType.Name;
And if you want to distinguish between actual types and generic type arguments, you can use Type.IsGenericParameter:
genericType.GetProperty("Prop").PropertyType.IsGenericParameter // true

Note that if you are are using C# 6, and require the generic type argument's name within it's defining class, you can get away without using reflection at all:
var name = nameof(T); // "T"
If you need the the generic type argument's name outside of it's class, you will need to use reflection (see Luaan's answer.)

Related

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>();
}

How to get the static type of a property?

I'm trying to reference the type of a property on a class and I can't figure out the syntax:
List<IChildInfo<typeof(MappingModel.identifier)>> mappings;
Is this possible in .NET?
public class MappingModel
{
public long identifier { get; set; }
}
The code you've presented won't work because the compiler has to create a specialized type for that particular list using the type you've specified.
The easiest way of fixing that would be to make a generic specialization "on the fly" ( or at run-time ).
example code:
// retrieve the property which type you want to get
var propertyInfo = typeof(MappingModel).GetProperty("identifier");
// get that property's type
Type propertyType = propertyInfo.PropertyType;
// now that you have a property type you can make a specialized generic type:
Type ichildtype = typeof(IChildInfo).MakeGenericType(propertyType);
// create a type definition for that particular list
Type listtype = typeof(List<>).MakeGenericType(ichildtype);
// create an instance of that list
Activator.CreateInstance(listtype);
Try this online
First examine the type of your surrounding class, then get its properties:
var p = typeof(MappingModel).GetProperties.FirstOrDefault(x => x.Name == "identifier");
Or also:
var p = typeof(MappingModel).GetProperty("identifier");
Now you can get the type of the property via PropertyType:
var t = p.PropertyType;
However as this is a runtime-information teher´s no way for the compiler to create an instance of a list of that type. You can create an interface that your type implements and then create a list of it:
var l = new List<IChildInfo<MyInterface>>();
where the type of MappingModel.identifier implements MyInterface. But this assumes IChildInfo to be co-variant:
interface IChildInfo<out T> { ... }
You need to use Reflection to that.
I'm not sure of what exactly you want to do but you can get all the property of a class doing :
typeof(MappingModel).GetProperties();
Then you can play with the properties.
You can get the type of the property, but you won't be able to use it as a generic argument using normal syntax. You can use MethodInfo to invoke a method that would use mappings. This answer may prove to be helpful to you.

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

IQueryable - Detect select into anonymous type [duplicate]

Is there anything to use, to determine if a type is actually a anonymous type? For example an interface, etc?
The goal is to create something like the following...
//defined like...
public static T Get<T>(this IAnonymous obj, string prop) {
return (T)obj.GetType().GetProperty(prop).GetValue(obj, null);
}
//...
//And then used like...
var something = new { name = "John", age = 25 };
int age = something.Get<int>("age");
Or is that just the beauty of an anonymous type? Nothing to identify it self because it takes a new shape?
Note - I realize that you can write an extension method for the object class, but that seems like a little overkill, in my opinion.
EDIT: The list below applies to C# anonymous types. VB.NET has different rules - in particular, it can generate mutable anonymous types (and does by default). Jared has pointed out in the comment that the naming style is different, too. Basically this is all pretty fragile...
You can't identify it in a generic constraint, but:
It will be a class (rather than interface, enum, struct etc)
It will have the CompilerGeneratedAttribute applied to it
It will override Equals, GetHashCode and ToString
It will be in the global namespace
It will not be nested in another type
It will be internal
It will be sealed
It will derive directly from object
It will be generic with as many type parameters as properties. (You can have a non-generic anonymous type, with no properties. It's a bit pointless though.)
Each property will have a type parameter with a name including the property name, and will be of that type parameter, e.g. the Name property becomes a property of type <>_Name
Each property will be public and read-only
For each property there will be a corresponding readonly private field
There will be no other properties or fields
There will be a constructor taking one parameter corresponding to each type parameter, in the same order as the type parameters
Each method and property will have the DebuggerHiddenAttribute applied to it.
The name of the type will start with "<>" and contain "AnonymousType"
Very little of this is guaranteed by the specification, however - so it could all change in the next version of the compiler, or if you use Mono etc.
As I recall, there is a [CompilerGenerated] marker... 2 secs
Plus the name will be freaky, and it will be a generic type ;-p
Actually, for a "get" etc I would probably just use a static (non-extension) method.
If you just want a way to get the value from an instance of an anon-type (at a later point in time), a lambda is probably the best option - note you need a few tricks to pull this off:
static void Main()
{
var foo = new { name = "John", age = 25 };
var func = Get(foo, x => x.age);
var bar = new { name = "Marc", age = 30 };
int age = func(bar);
}
// template here is just for type inference...
static Func<TSource, TValue> Get<TSource, TValue>(
TSource template, Func<TSource, TValue> lambda)
{
return lambda;
}
(edit re the comment) There definitely is this attribute:
var foo = new { A = "B" };
Type type = foo.GetType();
CompilerGeneratedAttribute attrib = (CompilerGeneratedAttribute) Attribute.GetCustomAttribute(
type, typeof(CompilerGeneratedAttribute)); // non-null, therefore is compiler-generated
For the purposes of extension methods there is no way to distinguish an anonymous type. Extension methods work by specifying a method for a compile time nameable type. Anonymous types are un-namable and therefore not visible at compile time. This makes them incompatible with extension methods.

Get the Class type for dynamic type?

I wrote some code :
public static object func()
{
return new { a = 1, b = 2 };
}
Console.WriteLine((func() as dynamic).a); //returns '1'.
If I can do : func() as dynamic so dynamic should be some kind of reference type / class.
I looked for its Class type but couldn't find any (via reflector).
what is its type ? ( reference type) ?
You can get the type via GetType() as normal.
That is an anonymous type, which is (as an implementation detail) a form of generic type. The name of the type is deliberately unpronounceable in c#.
If you look in reflector, there is probably an internal generic type somewhere ending in ’2 (to indicate 2 generic type parameters), with two properties "a" and "b", of the first and second generic type arguments respectively. It is a class, so a reference-type.
As a note:
new { a = true, b = 123.45 }
Would actually use the same generic type but with different generic type parameters.
Also; using dynamic doesn't change the object - it only changes how it is accessed.

Categories