Passing an instance of a dynamic type to a generic method in a generic class
To answer your question:
var type = typeof(abc);
object instanceToModify = new abc();
var typeToCreate = typeof(GenericClass<>).MakeGenericType(type);
var methodToCall = typeToCreate.GetMethod("GenericMethod");
var genericClassInstance = Activator.CreateInstance(typeToCreate);
methodToCall.Invoke(genericClassInstance, new[] { instanceToModify });
DEMO
But:
If your type is only known at runtime your instance must be handled in a variable declared as object
or dynamic
. In that case you can change your method signature to:
public object GenericMethod(object obj)
{
// modify the object in some (arbitrary) way
IEnumerable<FieldInfo> fields = obj.GetType().GetRuntimeFields();
foreach (var field in fields)
{
if (field.FieldType == typeof(string))
{
field.SetValue(obj, "This field's string value was modified");
}
}
return obj;
}
There's no need for a generic class/method.
How to call a Generic method on a dynamic type in C#
Since your type is dynamic, you won't know the type of the generic parameter until run-time. For this reason, you must also treat the function as dynamic, because you won't know the "type" of the function's generic signature until run-time.
You must use reflection to call a generic function dynamically. See How do I use reflection to call a generic method?
C# dynamically load generic class with dynamic type parameters per strings and strongly typed result
So i think ultimately your problem boils down to the fact that you want to load dynamic
types but then treat them as static
such that you can invoke methods using instance.MyMethod()
syntax. This is not possible (AFAIC) simply because instance.MyMethod()
is compiled down to IL and at that point compiler does not know what instance
is.
So provided you do not have any way of knowing what is the method you want to invoke, you have to go full dynamic route, i.e. use reflection APIs to invoke the right method.
So you would need to supply not just class name but also method name or have a convention e.g. always invoke method called 'Validate'
or something similar.
A simple listing below illustrates my point:
using System;
using System.Reflection;
namespace Shoes {
public interface IA { }
public class A : IA {}
public interface IB { }
public class B : IB {}
public class SomeKindOfModel<T1, T2> {
}
public class ConcreteModel<T1, T2> : SomeKindOfModel<T1, T2> {
public bool Validate() {
return true;
}
}
public class Program
{
public static void Main()
{
// since i don't have your Invoke.GetClassRef, i just did this, works in .net core
var type = Type.GetType($"Shoes.ConcreteModel`2");
var genType = type.MakeGenericType(new[] { typeof(A), typeof(B) });
var instance = Activator.CreateInstance(genType);
var result = genType.GetMethod("Validate", BindingFlags.Instance | BindingFlags.Public)
.Invoke(instance, null); // instead of null you can pass data etc.
Console.WriteLine(result); // prints True
}
}
}
How to use the `dynamic` when specifying generic type arguments in C#?
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"};
Calling a static method of generic class with a dynamic type c#
You need to use reflection. MakeGenericType
allows you to get the Type
with specific generic arguments and then you can get and call any method on it as you like.
void Main()
{
Type t = typeof(int);
Type at = typeof(A<>).MakeGenericType(t);
at.GetMethod("B").Invoke(null, new object[]{"test"});
}
public class A<T>
{
public static void B(string s)
{
Console.WriteLine(s+" "+typeof(T).Name);
}
}
As a performance optimization you could use reflection to get a delegate for each type which you then can invoke without further reflection.
Type t = typeof(int);
Type at = typeof(A<>).MakeGenericType(t);
Action<string> action = (Action<string>)Delegate.CreateDelegate(typeof(Action<string>), at.GetMethod("B"));
action("test");
Calling generic methods of objects of type dynamic
The reason list.Count()
gives a runtime error when list
is a dynamic
is that Count
is an extension method - Enumerable.Count<T>
- and extension methods can only be discovered at compile time. (Somebody correct me if I'm wrong on this - this is my understanding.)
Before getting the direct answer to your question, take a look at this little toy program.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Example
{
class Program
{
static void Main(string[] args)
{
IEnumerable<int> a = Enumerable.Range(1, 3);
IEnumerable b = a;
IEnumerable<double> c = b.SelectTimesPi();
foreach (var x in c)
{
Console.WriteLine(x);
}
Console.ReadLine();
}
}
static class Extensions
{
public static IEnumerable<double> SelectTimesPi(this IEnumerable source)
{
return source
.Cast<dynamic>()
.Select(x => Math.PI * x)
.Cast<double>();
}
}
}
Its output is the following.
3.14159265358979
6.28318530717959
9.42477796076938
The SelectTimesPi
extension method takes any IEnumerable<T>
where T
is only known at runtime, and then manipulates its elements as dynamic
values. The source
could be IEnumerable<byte>
, IEnumerable<short>
, IEnumerable<float>
, etc.
You could of course do the same thing with a non-extension method, like you asked. I just used that as the example since it looks like your aim is to ultimately create an extension method.
The trick is in the use of Enumerable.Cast<dynamic>
on an IEnumerable
.
Back to your original question. All you have to do is make your RenderTable
method take the list
as an IEnumerable
instead of a dynamic
, then use Enumerable.Cast<dynamic>
.
public static MvcHtmlString RenderTable(IEnumerable list, string id, string cssClass)
{
IEnumerable<dynamic> dynamicList = list.Cast<dynamic>();
int x = dynamicList.Count();
...
}
Now the call to Count
is not dynamically dispatched, so the extension method will work fine.
In summary:
IEnumerable<int> x = ...;
(x as IEnumerable).Cast<dynamic>().Count(); // does work
(x as dynamic).Count(); // does not work
Make Method Generic from Dynamic Type
You don't need to modify the method at all. What you need to do is take the Type
returned and use that to create a generic method using MakeGenericMethod that you can then invoke.
var dynamicType = DynamicType.CreateDynamicType(properties);
var method = mlContext.Model.GetType().GetMethod("CreatePredictionEngine");
System.Type type2 = ...; // however/wherever you get this instance of Type from
var generic = method.MakeGenericMethod(dynamicType, type2);
var param1 = ...; // however/wherever this comes from
var param2 = ...; // however/wherever this comes from
generic.Invoke(mlContext.Model, param1, param2);
That the type is generated dynamically by your CreateDynamicType
method is not relevant. You can use any instance of System.Type from any source as the instance on which you call MakeGenericMethod
.
Now to actually use your engine, assign it to a dynamic
. This allows you to dynamically call the Predict
method.
dynamic engine = (dynamic)genericMethod.Invoke(mlContext.Model, args);
var dest = engine.Predict(source)
Alternatively, you're right, you could create another generic method for Predict
and invoke that with reflection.
Without knowing the rest of your code, you'll have to continue dynamic calls using dest
until you're done with it, unless you can get back to a point where you can then call normal type safe C#.
Related Topics
Entity Framework/Sql2008 - How to Automatically Update Lastmodified Fields for Entities
Convert Base Class to Derived Class
Is Endinvoke() Optional, Sort-Of Optional, or Definitely Not Optional
How to Initialize a List<T> to a Given Size (As Opposed to Capacity)
Should You Declare Methods Using Overloads or Optional Parameters in C# 4.0
How to Make a Hyperlink Work in a Richtextbox
Connection String with Relative Path to the Database File
Winforms | C# | Autocomplete in the Middle of a Textbox
Can't Get SQL Server Compact 3.5/4 to Work with Asp .Net MVC 2
Path.Combine Absolute with Relative Path Strings
Cancelling a Task Is Throwing an Exception
Create Xml Nodes Based on Xpath
Webapi Streamcontent VS Pushstreamcontent
How to Make a Call to My Wcf Service Asynchronous
Should I Use Two "Where" Clauses or "&&" in My Linq Query