C# generics: Can you convert <T> ToString? - c#

Quick one here~
I want to convert < T > ToString so I can replace the variable with that type~
public void ChangePanel<T>(T Action){
FieldInfo Field = T.GetField(T.toString);
Field.SetValue(SomeObject, Action);
}
Also please let me know if there is a better way to do this!!
Edit: FYI the variables in SomeObject have the same name as type

You can use the typeof Keyword to get a Type instance, and the Type.Name Property to get the type's name.
public void ChangePanel<T>(T action)
{
Type typeOfObject = someObject.GetType();
Type typeOfAction = typeof(T);
FieldInfo field = typeOfObject.GetField(typeOfAction.Name);
field.SetValue(someObject, action);
}

Yes. ToString() is defined on the object class which everything derives from so I would expect you can call it on any type T. However, you need to call it on the parameter itself, not the type, so rather than doing T.ToString() you should be doing Action.ToString(). If you want to get the name of the type then you should use reflection rather than ToString.
Also, the reflection options are either;
typeof(T).Name
or
Action.GetType().Name

If you want to get the name of a generic type, then you can simply call typeof(T).Name:
public static string GetGenericTypeName<T>()
{
return typeof(T).Name;
}

The ToString method is a method, so you need parentheses to call it, and the case is important for identifiers:
FieldInfo Field = (typeof T).GetField(Action.ToString());
The GetField is a method of the Type class, so you need typeof to get the Type object for the T generic type.

Related

X is a variable but used like a type when trying to cast

I am passing a string of the name of the entity type I want to query and getting the type based on the string. I want to get the DbSet back and return an IQueryable. The problem is where I am doing (DbSet<tableEntity>) and getting the following error:
tableEntity is a variable but used like a type
when trying to cast. Is there a way to resolve this?
public object GetList(string tableEntity)
{
Type tableEntity = Type.GetType("TestProject." + typeName + ", TestProject");
var dbObject = (DbSet<tableEntity>)typeof(DbContext).GetMethod("Set", Type.EmptyTypes)
.MakeGenericMethod(tableEntity)
.Invoke(databaseContext, null);
return dbObject.AsQueryable();
}
EDIT
Just to add I don't have access to the type that's we I am passing the name through a string.
So it turns out that the entity type is literally not known, or knowable, at compile time. It has to be a string.
The only place you're using the type at compile time is in the cast to (DbSet<tableEntity>). Well, you may not need that. All you need from that type is to call AsQueryable(), and AsQueryable() is an extension method for IEnumerable, with generic and non-generic versions. IF we call it through non-generic IEnumerable, that's non-generic AsQueryable(), returning non-generic IQueryable. But we're returning object anyway, so hey. For the result of this thing to be useful, something somewhere must be doing a fair amount of reflection on it anyway, so the declared type is likely to be of little consequence.
See if this works:
public object GetList(string typeName)
{
Type tableEntity = Type.GetType("TestProject." + typeName + ", TestProject");
var dbObject = (System.Collections.IEnumerable)
typeof(DbContext).GetMethod("Set", Type.EmptyTypes)
.MakeGenericMethod(tableEntity)
.Invoke(databaseContext, null);
return dbObject.AsQueryable();
}
If it turns out you need generic IQueryable<TEntityType>, we'll have to use reflection to get MethodInfo for AsQueryable<TEntityType> for the unknown (at compile time) entity type, and call MakeGenericMethod(tableEntity) on that.
First try:
In the language, type parameters to generics must be actual types, not instances of the Type class. That's because they're resolved at compile time.
But that's no problem; to pass a type parameter to a generic method, simply write a generic method with a type parameter.
You can't do this:
var stuff = GetList("MyTableEntityClass");
But this is just as good:
var stuff = GetList<MyTableEntityClass>();
...
public object GetList<TTableEntity>()
{
var dbObject = (DbSet<TTableEntity>)typeof(DbContext)
.GetMethod("Set", Type.EmptyTypes)
.MakeGenericMethod(typeof(TTableEntity))
.Invoke(databaseContext, null);
return dbObject.AsQueryable();
}
Reflection is different; that's why we pass typeof(TTableEntity) to MakeGenericMethod().
And once we're using an actual type that the compiler can check, we can do better with our return type, too:
public IQueryable<TTableEntity> GetList<TTableEntity>()
{
var dbObject = (DbSet<TTableEntity>)typeof(DbContext)
.GetMethod("Set", Type.EmptyTypes)
.MakeGenericMethod(typeof(TTableEntity))
.Invoke(databaseContext, null);
return dbObject.AsQueryable();
}
Since, as Ed mentioned, you don't use the table entity type at compile time, why not just use the non-generic databaseContext.Set (tableEntity).AsQueryable ()? But if you've set your heart on Set<>, try this:
public object GetList(string tableEntity)
{
Type tableEntity = Type.GetType("TestProject." + typeName + ", TestProject");
return GetType ()
.GetMethod ("GetListHelper")
.MakeGenericMethod (tableEntity)
.Invoke (this) ;
}
public object GetListHelper<T> () where T : class
{
var dbObject = databaseContext.Set<T> (null) ;
return dbObject.AsQueryable();
}

How to get and use class/entity type by reflection?

I have these entities that are being called at runtime and I need to be able to return an IQueryable<EntityObject> based on the entity type being called that particular time by string. Let's say the entity is types of food and the class name is Food, so...
return Repository.Read<Food>(); //this is what I am trying to accomplish
However, I don't know that it is Food until runtime and is such only given as a string, so I use reflection:
Type t = Type.GetType(lookupEntityName); //where lookupEntityName = "Food"
How can I use this Type t to replace 'Food' in the original line of code from above:
return Repository.Read<HERE>(); // use 't' to repalce "HERE"
Supposing that your method only contains a return statement (because you have only posted that), you could do something like this (warning: this wasn't tested):
public static IQueryable<T> Read<T>()
{
return Repository.Read<T>();
}
And you could use it like this:
IQueryable<Food> food = Read<Food>();
You have to use the MethodInfo.MakeGenericMethod Method to create your generic method at runtime.
var openMethod = typeof(Repository).GetMethod(nameof(Repository.Read), ...);
var closedMethod = openMethod.MakeGenericMethod(t);
return closedMethod.Invoke(...);
If you need to call a generic method, you must get the MethodInfo of that function and create a generic MethodInfo for the appropiate type.
This is a helper function to do this:
public MethodInfo GetGenericMethod(string MethodName, Type SourceType, Type TargetType)
{
var mInfo = SourceType.GetMethod(MethodName);
return mInfo.MakeGenericMethod(TargetType);
}
And now you can do this:
Type t = Type.GetType(lookupEntityName);
Type tSrc = typeof(Repository);
var result = GetGenericMethod("Read", tSrc, t).Invoke(Repository);
If Read is an static method then pass null to the invoke.

C# Func<T,TResult> arguments validation

Imagine the Func Func<Arguments, bool?>, where Arguments is an abstract class. Somewhere, for some reason I create a list of these functions with all kind of derived classes as arguments. Of course the type of Arguments is important for validation before the Func is called. Is there a way to get the type of Arguments?
e.g.:
public bool? test(Arguments arg) {
Func test = Func<SomeArguments, bool?>;
Type argType = GetFirstArgumentType(test); // gives SomeArguments.GetType();
if (arg.GetType() == argType) {
return test(new SomeArguments());
}
return null;
}
You can use Type.GetGenericArguments to get the System.Type of the first generic argument to your Func<T,bool?>.
That being said, it would likely be easier to store a Dictionary<Type, Delegate> to hold your types, and just do a direct lookup instead.
Based on your description, " Somewhere, for some reason I create a list of these functions with all kind of derived classes as arguments. " I might suggest that you use a parameter constraint:
public bool? test<T>(T arg) where T :Arguments, new()
{
var type = typeof(T);
// ...
}
This will get you the type checking you describe.

How to specify the type of an anonymous type while using a generic type

The title is pretty confusing. I will try to explain with an example. Consider the code below:
String[] str={"Apple","Banana","Cherry","Orange"};
var anoCollection=from e in str select new
{
ch=e[0],
length=e.Length
}
dataGridView.DataSource=anoCollection.ToList(); //TypeInitializationException
I feel that I need to mention the type in above case for the ToList<T>() method. But how can I mention an anonymous type here?
It is never possible to mention an anonymous type directly, but you should not need to. Generic type inference means that you don't need to specify the <T> in .ToList<T>() - the compiler will automatically inject the invented type.
There are only a few ways to refer to an anonymous type:
via someObj.GetType(), where someObj is an instance of an anonymous type
via generics, as a T, by calling a generic method via generic type inference (as in ToList())
various other usages of reflection, pulling in the T via GetGenericTypeParameters()
This may be not what you are asking for, but if you later want to use the DataBoundItem for a row, you can do it this way:
var item = TypeExtensions.CastByPrototype(row.DataBoundItem, new { ch = 'a', length = 0});
//you can use item.ch and item.length here
Trace.WriteLine(item.ch);
with the support of this method:
public static class TypeExtensions
{
public static T CastByPrototype<T>(object obj, T prototype)
{
return (T)obj;
}
}

Is this possible to code like this : public static T GetValue(string name,Type T){...}

I need to code like this:
public static T GetValue(this SerializationInfo si, string name,Type T)
{
return (T) si.GetValue(name, typeof (T));
}
I already know that the following code can work properly
public static T GetValue<T>(this SerializationInfo si, string name)
{
return (T) si.GetValue(name, typeof (T));
}
and my code is in c#,
can anyone help?
The return type T in the first example does not refer to any valid type: T in that case is simply the name of a parameter passed to the method.
You either know the type at design time or you don't, and if you don't then your only choice is to return the type Object, or some other base type or interface.
No you cannot do that, because generics are assessed at compilation (and you are asking for dynamic generics). Can you provide some more context on the usage?
How are you getting your t parameter to pass to your desired example? If it's simply by typeof(int) as a parameter, then why not use the generic exmaple?
Consider this example:
Type t = GetTypeInfoBasedOnNameInAFile();
int a = GetValue(someSerializationInfo, "PropertyName", t);
How can the compiler know that Type t is going to be castable to int at runtime?
What you could do is have GetValue return an Object and then:
Type t = GetTypeInfoBasedOnNameInAFile();
int a = (int)GetValue(someSerializationInfo, "PropertyName", t);
But of course, if you are doing that it implies you know the expected types at compile time, so why not just use a generic parameter.
You can perhaps achieve what you are after (I'm not sure on the context/usage) by using dynamic variables.
You can do a runtime conversion to a type:
Convert.ChangeType(sourceObject, destinationType);
I believe that is the syntax. Of course, this will throw an exception if the cast is not possible.

Categories

Resources