C# Creating an Unknown Generic Type at Runtime

c# Creating an unknown generic type at runtime

I think you're looking for the MakeGenericType method:

// Assuming that Property.PropertyType is something like List<T>
Type elementType = Property.PropertyType.GetGenericArguments()[0];
Type repositoryType = typeof(GenericRepository<>).MakeGenericType(elementType);
var repository = Activator.CreateInstance(repositoryType);

Create generic repository of unknown type at run-time

Just declare your repository and UoW method with the necessary type constraint for BaseClass:

public interface IRepository<TEntity> where TEntity : BaseClass
...
public class Repository<TEntity> : IRepository<TEntity> where TEntity : BaseClass
...
public virtual IRepository<TEntity> Repository<TEntity>() where TEntity : BaseClass

and then you can do that:

unit_of_work.Repository<BaseClass>().Insert(<whatever>);

This works because of generic contravariance.

Create instance of an unknown generic class Type-object at runtime?

The most generic way I can think of is by loading the target action type by name where the number after the backtick (aka grave accent) represents the number of generic arguments you need.

Unfortunately Action<> is found in a different assembly (mscorlib) to the other action types so it needs to be handled differently when using this approach.

public static Type GetActionDelegateType(params Type[] typeArgs)
{
var argCount = typeArgs.Length;
if (argCount == 0) return typeof (Action);
var defType = argCount == 1
? typeof (Action<>) //special case since it's found in mscorlib
: Type.GetType(string.Format("System.Action`{0}, {1}",
argCount,
typeof (Action).Assembly.FullName));
return defType.MakeGenericType(typeArgs);
}

You can see the above code in action using this test code:

for (var i = 0; i <= 4; i++)
{
var typeArgs = Enumerable.Repeat(typeof (string), i).ToArray();
Console.WriteLine(GetActionDelegateType(typeArgs));
}

Casting to unknown derived type at runtime?

This has to do with covariance and contravariance.

The reason the cast fails is that, if you were allowed to do what you are trying to do, you would be able to pass an incompatible type to your handler. For example, your approach would allow this:

ICommandHandler<Command> focusHandler = new FocusHandler();
Command closeCommand = new CloseCommand();
focusHandler.Handle(closeCommand);

One way to deal with types that are not known at compile time is to use reflection. You mentioned Provider.GetRequiredService so I'm going to assume that you are using Microsoft.Extensions.DependencyInjection. You can do the following:

  • Register all of your handlers as their actual types
  • Use reflection to create the actual handler type from the actual command type
  • Use that type to get the handler from DI
  • Use reflection to call the handler

Register your handlers like this:

services.AddTransient<ICommandHandler<FocusCommand>, FocusHandler>();
services.AddTransient<ICommandHandler<CloseCommand>, CloseHandler>();

Implement your Invoke method like this:

public void Invoke(Command command)
{
Type commandType = command.GetType();
Type handlerType = typeof(ICommandHandler<>).MakeGenericType(commandType);
var handler = serviceProvider.GetService(handlerType);
var mi = handlerType.GetMethod("Handle", 0, new[] { commandType });
mi.Invoke(handler, new[] { command });
}

How to create an instance of generic type whose constructor requires a delegate function parameter?

Constructing a delegate of an unknown type dynamically isn't as easy as using reflection to call a method, so the easiest option is to just write a statically typed method to construct the delegate, and then just call it using reflection.

public class DelegateCreator
{
public static Func<T> MakeConstructorStatically<T>()
{
return Activator.CreateInstance<T>;
}

public static object MakeConstructorDynamically(Type type)
{
return typeof(DelegateCreator)
.GetMethod(nameof(MakeConstructorStatically))
.MakeGenericMethod(type)
.Invoke(null, Array.Empty<object>());
}
}

How do you call a generic method if you only know the type parameter at runtime?

You need to call it using reflection:

var method = typeof(SomeClass).GetMethod("SomeMethod");
method.MakeGenericMethod(someType).Invoke(...);

How to cast to unknown generic runtime type (C# ChangeType equivalent)

In the declaration of your State class, you forgot to specify the generic parameter of the widget.

Instead of:

class _PagedScrollerState<T> extends State<PagedScroller> {

do:

class _PagedScrollerState<T> extends State<PagedScroller<T>> {

Create instance of an unknown generic class Type-object at runtime?

The most generic way I can think of is by loading the target action type by name where the number after the backtick (aka grave accent) represents the number of generic arguments you need.

Unfortunately Action<> is found in a different assembly (mscorlib) to the other action types so it needs to be handled differently when using this approach.

public static Type GetActionDelegateType(params Type[] typeArgs)
{
var argCount = typeArgs.Length;
if (argCount == 0) return typeof (Action);
var defType = argCount == 1
? typeof (Action<>) //special case since it's found in mscorlib
: Type.GetType(string.Format("System.Action`{0}, {1}",
argCount,
typeof (Action).Assembly.FullName));
return defType.MakeGenericType(typeArgs);
}

You can see the above code in action using this test code:

for (var i = 0; i <= 4; i++)
{
var typeArgs = Enumerable.Repeat(typeof (string), i).ToArray();
Console.WriteLine(GetActionDelegateType(typeArgs));
}

call a generic method with an object of an unknown type

You are only calling ToString on the key and value, so simply have this method take an IDictionary (non-generic), you are not using anything in there that is type-specific to T or U.

You can then simply cast all arguments to IDictionary:

var d = arg as IDictionary;

if (d != null)
{
var res = DictionaryToString(d);
}

You may also need to amend the DictionaryToString implementation:

static string DictionaryToString(IDictionary d)
{
var vals = new List<string>();

foreach (DictionaryEntry de in d)
{
vals.Add(de.Key.ToString() + ": " + de.Value.ToString());
}

return String.Join("\n", vals);
}

Alternatively, if you really want to use LINQ, you could try casting to dynamic (it isn't possible to cast to anything else as this could be a generic dictionary (KeyValuePair<>) or non-generic hashtable (DictionaryEntry)):

var valueStrings = d.Cast<dynamic>().Select(de => de.Key.ToString() + ": " + de.Value.ToString());
return string.Join("\n", valueStrings);

This basically "duck types" the existence of the Key and Value properties.



Related Topics



Leave a reply



Submit