I have a generic static method which registers a interface and I need to write that using c# reflection.
Services.AddService<ITBroker>(new TBrokerService());
I tried following code but it is not working
Type[] externTBrokerService = Assembly.LoadFrom("Business.dll").GetTypes();
Type[] externService = Assembly.LoadFrom("ServiceModel.dll").GetTypes();
Type iTBroker = externITBroker[12];
MethodInfo method = externService[1].GetMethods()[2];
//Gets Add Service method
MethodInfo generic = method.MakeGenericMethod(iTBroker);
//Make method generic
generic.Invoke(null,new object[] { externTBrokerService[0]});
//invoke the service
Above code gives me very generic exception of parameters.
What is the write way to write reflection for above code?
As it was in comments:
Note that externTBrokerService[0] is a Type and not an instance of that type.
Having that I feel a need to include sense of other comments as part of my answer.
Type iTBroker = externITBroker[12];
this is wrong! And sooner or later this will fail to find your type as the order of types in this collection is undetermined and can change. You should do it like this:
Type iTBroker = externITBroker.Single(x => x.Name == "ITBroker");
This is far form foolproof so be sure that the condition gives you unique result.
or simply load that type directly by (assuming that this is the AssemblyQualifiedName of your type):
Type.GetType("Business.ITBroker, Business");
To find method on your type there is a method Type.GetMethod one of its overloads will be sufficient to find your method.
To create instance of your type that needs to be passed as argument you can use
Activator.CreateInstance(brokerServiceType);
Related
In my code I have declared an interface as follows:
interface IGeneric
{
T GetOfType<T>();
}
And I want to invoke the interface's method with a generic type only known at runtime. This is how I do it currently, and it works:
Type genericArgument = ...
object interfaceImplementation = ...
MethodInfo methodInfo = typeof(IGeneric).GetMethod("GetOfType").MakeGenericMethod(genericArgument);
methodInfo.Invoke(interfaceImplementation, null);
but because I have to call this part of code quite often, I would like to cache the method info in a delegate. I tried this delegate definition
private delegate T GetOfTypeDelegate<T>();
and tried to create a delegate using the method info I retrieved like shown above like this:
GetOfTypeDelegate<?> deleg = (GetOfTypeDelegate<?>) Delegate.CreateDelegate(typeof(GetOfTypeDelegate<?>), methodInfo);
but since I don't know the type of the generic argument at compile time, I don't know what to put where I used the ? or how to make this work at all.
Any help is gladly appreciated.
I'd advise having generic and non-generic versions of the method, much like List<T> implements IEnumerable<T> while also explicitly implementing System.Collections.IEnumerable.
"Type known only at runtime" is exactly what generics aren't intended to be used for. The way you're calling this method, you only ever get object out of it anyway. Better to have a real ordinary non-generic method that just returns object.
T GetOfType<T>();
object GetOfType(Type t);
You don't even need to worry about overload resolution. There's some extra burden placed on the class implementing the interface, admittedly. But as you've seen, there's going to be a burden somewhere.
Assume we have a static method "Instance" in a type: "SomeType"
MethodInfo instanceMethod = SomeType.GetMethod("Instance");
The method returns an object of a type that is not available in my code as it does not reference the assembly where that class is defined.
I would like then, to cast it to "object"
Like this:
Delegate.CreateDelegate(typeof(Func<object>), null, "Instance")
However I get this exception:
System.ArgumentException: Error binding to target method.
The CreateDelegate overload that you appear to be using only works for instance methods, not static ones. If you pass the MethodInfo instead of the name "Instance", you'll be using an overload that will work.
Also, Func<object> isn't compatible with just any type. You can create a Func<> that matches the method's return type with MakeGenericType.
Type funcType = typeof(Func<>).MakeGenericType(instanceMethod.ReturnType);
Delegate del = Delegate.CreateDelegate(funcType, null, instanceMethod);
As an aside, I'd name the method GetInstance instead of Instance, to make things clearer. (if it were a property, Instance would be appropriate)
First let me say, that what I want to do is get the value of a property in a generic class that may be overriden by class that inherits from it. Think of it in the base class as a default value, that the inheritor of the class can override to set their own Default value.
I have tried to use reflection directly on the type, using the System.Reflection.FieldInfo.GetValue but this does not work for classes with generic types. So I think that I need to instantiate the class to be able to see what the value is.
The "types" I have I retrieved by reading the Dlls in the bin and using Reflection to find the types that inherit from my interface.
I am using .NET 4.5
here is documentation that seems like it explains exactly what I need to do
http://msdn.microsoft.com/en-us/library/b8ytshk6.aspx
In this documentation the only difference I can see is how we got our types, I looked in the bin for types and they simply called typeof(), Since types are so complex it seems this may be a likely mis-match but I cannot see what is missing(if anything)
foreach (var item in types)
{
var ts = item.GetField("DefaultTimeToExpire");
Type[] typeArguments = item.GetGenericArguments();
if (ts != null)
{
var t = item.MakeGenericType(typeArguments);
var obj = Activator.CreateInstance(t);
var timespan = obj.DefaultTimeToExpire;
subscriberInfos.Add(new Tuple<string, Type, TimeSpan>(item.Name, item, timespan));
}
}
I am calling GetField to look for Items that have a field "DefaultTimeToExpire" so far this part works well to find the type I need.
Next I call GetGenericArguments which returns an expected array of the type Arguments.
then I call MakeGenericType
and finally Create instance wich gives me the error message
"Cannot create an instance of BusinessLogic.TestSubscriberXXX`1[Message] because Type.ContainsGenericParameters is true."
This looks like exactly what I am supposed to do.
Thanks
In order to instantiate a generic type, you need to know the actual values (types) that should be substituted for its type parameters. The GetGenericArguments() method, being a form of reflection, only gives you the type arguments, not their actual values. The values are up to you... that is the entire point of generics.
If item is a type like List<T> then item.GetGenericArguments() will return an array containing a fake "type" representing the type parameter T (with its IsGenericParameter property set to true). Therefore, passing that parameter type back into item.MakeGenericType() will simply create another open generic type equivalent to the original. To close the generic type so that it can be instantiated you need to provide an actual (non-parameter) type argument, such as int.
For example, typeof(List<>).MakeGenericType(typeof(int)) will return typeof(List<int>), while typeof(List<>).MakeGenericType(typeof(List<>).GetGenericArguments()) will simply return typeof(List<>) again. This is what is happening in your code.
I'm sorry if that is a bit opaque, I don't know how else to explain it. The bottom line is that a type like List<T> is only useful if you have a type you want to substitute in place of T.
I would like some explanation of you experts in C# 4.0 dynamic.
I have a fluent builder class to help configure an object before creating it. This interface has a method SetParameters(...):
public FluentBuilder<TInterface> SetParameters(dynamic parameters)
{
_parameters = parameters;
return this;
}
I'm doing this to consume the fluent interface:
var order = new Order();
/* Setting up parameters */
dynamic parameters = new ExpandoObject();
parameters.Transaction = transactionObj;
parameters.CurrentPrincipal = Thread.CurrentPrincipal;
var proxiedOrder = ObjectProxyFactory
.Configure<IOrder>(order)
.FilterMethods(o => o.InsertOrder())
.AddPreDecoration(AppConcerns.JoinSqlTransaction)
.AddPreDecoration(AppConcerns.EnterLog)
.AddPostDecoration(AppConcerns.ExitLog)
.AddPostDecoration(AppConcerns.SecurityCheck)
.SetParameters(parameters)
.Teste() //this method doesn't exist in the fluent builder
.CreateProxy();
var result = proxiedOrder.InsertOrder();
As commented in the above snippet, the method called Teste() doesn't exists in the fluent interface, but intelissense allow write anymethod after I call SetParameters like it returning dynamic, but as you see in code, SetParameters returns FluentInterface that is not dynamic.
The code above compiles sucessfully by in runtime will fail because in runtime the method Teste() will not be found in FluentBuilder class.
To resolve this problem in design-time, and to get correct Intelissense, I need to cast the parameter to the ExpandoObject class:
var proxiedOrder = ObjectProxyFactory
.Configure<IOrder>(order)
.FilterMethods(o => o.InsertOrder())
.AddPreDecoration(AppConcerns.JoinSqlTransaction)
.AddPreDecoration(AppConcerns.EnterLog)
.AddPostDecoration(AppConcerns.ExitLog)
.AddPostDecoration(AppConcerns.SecurityCheck)
.SetParameters((ExpandoObject)parameters) //cast to ExpandoObject
.Teste() //now intelissense is giving me an "red" error and solution will not compile
.CreateProxy();
var result = proxiedOrder.InsertOrder();
I've found that, anytime I pass a C# dynamic parameter in any method chaining, after that method receiving the dynamic parameter, the subsequent calls to methods will behave like returning a C# dynamic object, even if the return type of the method it's not dynamic.
Is it a bug ? Or is this expected to happens ?
It's expected to happen. Any method call involving a dynamic argument is resolved dynamically - the exact overload can't be determined until execution time, so the return type is unknown at compile time, so it's treated as being dynamic. In some cases the C# compiler could infer more information (e.g. if it's a static method call) but for simplicity it doesn't. Only a variable few expressions involving dynamic values have non-dynamic types. (From memory, the is operator is always bool, and a constructor is always assumed to return the type being constructed.)
EDIT: I've finally found the spec reference. From section 7.6.5:
An invocation-expression is dynamically bound (ยง7.2.2) if at least one of the following holds:
The primary-expression has compile-time type dynamic.
At least one argument of the optional argument-list has compile-time type dynamic and the primary-expression does not have a delegate type.
In this case the compiler classifies the invocation-expression as a value of type dynamic.
In C# I want to create a generic method that:
Accepts a MethodInfo object as a parameter.
Returns the object that is returned when the MethodInfo is invoked.
The source of my confusion is that I want the method to be generically typed to the same return type as the MethodInfo object that gets passed in.
You cannot do this. By definition, generics are a compile-time construct, while the return type of a particular MethodInfo is something that is only known at runtime (when you receive a specific MethodInfo instance), and will change from call to call.
Pavel Minaev is right,
My suggestion in this case (of course i don't know the whole context) is use a method that returns a dynamic type, of course is that wouldn't be typed.
public dynamic MyMethod(MethodInfo methodInfo)
Or since you know what is the return type, put that in the method call:
public T MyMethod<T>(MethodInfo methodInfo)
of course you gonna get in trouble inside the method mapping the conversions.
but you can also put the conversion in a parameter using lambda, like:
public T MyMethod<T>(MethodInfo methodInfo, Func<object, T> conversion)
i think the call of the method will be very clear, like:
Console.WriteLine(MyMethod(methodInfo, (a) => Convert.ToString(a)));