I have a list of types (System.Type) which need te be queried on the database.
For each of this types, I need to call the following extensionmethod (which is part of LinqToNhibernate):
Session.Linq<MyType>()
However I do not have MyType, but I want to use a Type instead.
What I have is:
System.Type typeOne;
But I cannot perform the following:
Session.Linq<typeOne>()
How can I use a Type as a Generic parameter?
You can't, directly. The point of generics is to provide compile-time type safety, where you know the type you're interested in at compile-time, and can work with instances of that type. In your case, you only know the Type so you can't get any compile-time checks that any objects you have are instances of that type.
You'll need to call the method via reflection - something like this:
// Get the generic type definition
MethodInfo method = typeof(Session).GetMethod("Linq",
BindingFlags.Public | BindingFlags.Static);
// Build a method with the specific type argument you're interested in
method = method.MakeGenericMethod(typeOne);
// The "null" is because it's a static method
method.Invoke(null, arguments);
If you need to use this type a lot, you might find it more convenient to write your own generic method which calls whatever other generic methods it needs, and then call your method with reflection.
To do this you need to use reflection:
typeof(Session).GetMethod("Linq").MakeGenericMethod(typeOne).Invoke(null, null);
(assuming that Linq<T>() is a static method on the type Session)
If Session is actually an object, you'll need to know where the Linq method is actually declared, and pass in Session as an argument:
typeof(DeclaringType).GetMethod("Linq").MakeGenericMethod(typeOne)
.Invoke(null, new object[] {Session});
I have one general method which call Call Generic Method Through Reflection
/// <summary>
/// This method call your method through Reflection
/// so i wil call the method like CallGenericMethodThroughReflection<Session>(assemblyQualifiedName,Linq,false,new[] { file })
/// </summary>
/// <typeparam name="T">Call method from which file</typeparam>
/// <param name="assemblyQualifiedName">Your can get assemblyQualifiedName like typeof(Payroll.Domain.Attendance.AttendanceApplicationMaster).AssemblyQualifiedName</param>
/// <param name="methodName"></param>
/// <param name="isStaticMethod"></param>
/// <param name="paramaterList"></param>
/// <param name="parameterType">pass parameter type list in case of the given method have overload </param>
/// <returns>return object of calling method</returns>
public static object CallGenericMethodThroughReflection<T>(string assemblyQualifiedName, string methodName,bool isStaticMethod ,object[] paramaterList,Type[] parameterType = null)
{
try
{
object instance = null;
var bindingAttr = BindingFlags.Static | BindingFlags.Public;
if (!isStaticMethod)
{
instance = Activator.CreateInstance<T>();
bindingAttr = BindingFlags.Instance | BindingFlags.Public;
}
MethodInfo MI = null;
var type = Type.GetType(assemblyQualifiedName);
if(parameterType == null)
MI = typeof(T).GetMethod(methodName, bindingAttr);
else
MI = typeof(T).GetMethod(methodName, bindingAttr,null, parameterType, null);//this will work in most case some case not work
if (type == null || MI == null) // if the condition is true it means given method or AssemblyQualifiedName entity not found
return null;
var genericMethod = MI.MakeGenericMethod(new[] { type });
return genericMethod.Invoke(instance, paramaterList);
}
catch (Exception ex)
{
throw ex;
}
}
Related
I have a method with an out parameter that tries to do a type conversion. Basically:
public void GetParameterValue(out object destination)
{
object paramVal = "I want to return this. could be any type, not just string.";
destination = null; // default out param to null
destination = Convert.ChangeType(paramVal, destination.GetType());
}
The problem is that usually someone would call this like:
string output;
GetParameterValue(output);
This will fail because of:
destination.GetType()
destination is null, so we can't call .GetType() on it. We also can not call:
typeof(destination)
because destination is a variable name not a type name.
So is there any way to get the type of an object that is set to null? I would think there would have to be a way to know what type a storage location is without it being assigned anything.
Just to give a bit more info, I am trying to make a utility method that will grab the output parameters of an Oracle stored procedure. The issue is that DbParameter.Value is of type object.
What would be ideal would be for the developers to do something like:
string val = GetParameterValue("parameterName");
The notable thing is that there is no casting of types. In practice, you don't know the lparam of the "equals", so I went with:
string val;
GetParameterValue("parameterName", out val);
And figured within the method, I would know the destination type of the output variable. I guess that was a bad assumption. As an alternative, I also wrote the method:
public T GetParameterValue<T>(string paramName)
So the developers can do:
string val = GetParameterValue<string>("parameterName");
I find the explicit "string" declaration to be repetitive, especially since in practice, the destination if probably an object property and the oracle data type could change (think ORM):
MyObj.SomeProp = GetParameterValue<MyObj.SomeProp.GetType()>("parameterName");
But again, if MyObj.SomeProp is null, that .GetType() call fails. The VM has to know the type of MyObj.SomeProp, even when its null, right? or else how would it catch cast exceptions?
To partially solve my own problem, I can do:
MyObj.SomeProp = GetParameterValue<typeof(MyObj).GetField("SomeProp").GetType()>("parameterName");
The whole idea was to not have to explicitly use the Type in more than one place, so that if the data type changes, it only has to be changed in the destination object (MyObj.SomeProp) and in the DB. There has to be a better way...
So is there any way to get the type of an object that is set to null? I would think there would have to be a way to know what type a storage location is without it being assigned anything.
Not necessarily. The best that you can say is that it is an object. A null reference does not point to any storage location, so there is no metadata from which it can make that determination.
The best that you could do is change it to be more generic, as in:
public void GetParameterValue<T>(out T destination)
{
object paramVal = "Blah";
destination = default(T);
destination = Convert.ChangeType(paramVal, typeof(T));
}
The type of T can be inferred, so you shouldn't need to give a type parameter to the method explicitly.
It's possible if you don't mind declaring your method as a generic. Try this.
class Program
{
public static void GetParameterValue<T>(out T destination)
{
Console.WriteLine("typeof(T)=" + typeof(T).Name);
destination = default(T);
}
static void Main(string[] args)
{
string s;
GetParameterValue(out s);
int i;
GetParameterValue(out i);
}
}
The following extension method returns the type of its parameter as it was declared, regardless of its contents:
using System;
namespace MyNamespace
{
public static class Extensions
{
/// <summary>
/// Gets the declared type of the specified object.
/// </summary>
/// <typeparam name="T">The type of the object.</typeparam>
/// <param name="obj">The object.</param>
/// <returns>
/// A <see cref="Type"/> object representing type
/// <typeparamref name="T"/>; i.e., the type of <paramref name="obj"/>
/// as it was declared. Note that the contents of
/// <paramref name="obj"/> are irrelevant; if <paramref name="obj"/>
/// contains an object whose class is derived from
/// <typeparamref name="T"/>, then <typeparamref name="T"/> is
/// returned, not the derived type.
/// </returns>
public static Type GetDeclaredType<T>(
this T obj )
{
return typeof( T );
}
}
}
Since this is an extension method, its argument can be a null reference, and all of the following works OK:
string myString = "abc";
object myObj = myString;
Type myObjType = myObj.GetDeclaredType();
string myNullString = null;
object myNullObj = myNullString;
Type myNullObjType = myNullObj.GetDeclaredType();
Note that myObjType and myNullObjType will both be set to System.Object, not System.String.
If you actually want the type of obj's contents when it's not null, then change the return line to:
return (obj != null) ? obj.GetType() : typeof( T );
Currently, you have no way of knowing what gets passed into the method. You can convert it into a generic method like this:
public void GetParameterValue<T>(out T destination)
{
...
}
The type of your destination variable is always System.Object. You could just return
Convert.ChangeType(paramVal, System.Object).
#Rally25s:
string val;
GetParameterValue("parameterName", out val);
It's unclear from your message (in the answers) what the problem with that one was. If declared as:
void GetParameterValue<T>(string parameterName, out T val) { }
Than the call, as you wrote it above, will work (you don't need to specify the type). I'm guess that didn't work for you because you can't use a property as an "out" parameter. The way around that is to use both methods:
T GetParameterValue<T>(string parameterName, T ununsed) { }
This would be called like this:
MyObj.SomeProp = GetParameterValue("parameterName", MyObj.SomeProp);
which is rather kludgey, but not the worse method presented.
A different method, which I've used in C++, but haven't tried yet in C#, is to have GetParameterValue() some object of you own design, and then implement a number of implicit cast operators for it.
class ParameterHelper
{
private object value;
public ParameterHelper(object value) { this.value = value; }
public static implicit operator int(ParameterHelper v)
{ return (int) v.value; }
}
ParameterHelper GetParameterValue( string parameterName);
MyObj.SomeProp = GetParameterValue("parameterName");
I don't think it is possible to get the type when the value is null. Also, since you are calling inside GetParameterValue, the best you could do (when the value is null) is to get the type of the "destination" parameter which is "object". You might consider passing the Type as a parameter to GetParameterValue where you have more information, such as:
public void GetParameterValue(Type sourceType, out object destination) { //... }
If there is no instance, there is no instance type.
The best you can do is use the type of the reference, which means if you have an object reference (as in the method in the question), the reference type is object.
You probably shouldn't be trying to convert a null instance of one type into a null instance of another type...
In your example it would be null of type System.Object.
Does your example even compile? I get a "cannot convert from 'out string' to 'out object'" error.
At a theoretical level isn't a null really the same as a void pointer in C, which is to say that it holds a memory address and that's it? If so then it is similar to the case of a division by zero in Mathematics where the result is undefined.
One could do the following for this line:
string val = GetParameterValue<string>("parameterName");
Just remove that first string and now there isn't the repetition:
var val = GetParameterValue<string>("parameterName");
Not necessarily what you are looking for, though there is the question of how does one interpret null?
//**The working answer**
//**based on your discussion eheheheheeh**
public void s<T>(out T varName)
{
if (typeof (T) == typeof(HtmlTable))
{
//////////
}
}
protected void Page_Load(object sender, EventArgs e)
{
HtmlTable obj=null ;
s(out obj);
}
http://msdn.microsoft.com/en-us/library/58918ffs.aspx
or
private Hashtable propertyTable = new Hashtable();
public void LoadPropertyTypes()
{
Type t = this.GetType();
System.Reflection.MemberInfo[] memberInfo = t.GetMembers();
foreach (System.Reflection.MemberInfo mInfo in memberInfo)
{
string[] prop = mInfo.ToString().Split(Convert.ToChar(" "));
propertyTable.Add(prop[1], prop[0]);
}
}
public string GetMemberType(string propName)
{
if (propertyTable.ContainsKey(propName))
{
return Convert.ToString(propertyTable[propName]);
}
else{
return "N/A";
}
}
in that way we can use switch to manage different property types.
I have a class with a private static method with an optional parameter. How do I invoke it from another class via Reflection? There is a similar question, but it does not address static method or optional parameters.
public class Foo {
private static void Bar(string key = "") {
// do stuff
}
}
How do I invoke Foo.Bar("test") and Foo.Bar() (e.g. without passing the optional parameter)?
Optional parameter values in C# are compiled by injection those values at the callsite. I.e. even though your code is
Foo.Bar()
The compiler actually generates a call like
Foo.Bar("")
When finding the method you need to treat the optional parameters as regular parameters.
var method = typeof(Foo).GetMethod("Bar", BindingFlags.Static | BindingFlags.NonPublic);
If you know exactly what values you want to invoke the method with you can do:
method.Invoke(obj: null, parameters: new object[] { "Test" });
If you only have some of the parameters and want to honor the values of the default ones you have to inspect the method's ParameterInfo objects to see if the parameters are optional and what those values are. For example to print out the default values of those parameters you could use the following code:
foreach (ParameterInfo pi in method.GetParameters())
{
if (pi.IsOptional)
{
Console.WriteLine(pi.Name + ": " + pi.DefaultValue);
}
}
Using this class
public class Foo
{
private static void Bar(string key = "undefined key", string value = "undefined value")
{
Console.WriteLine(string.Format("The key is '{0}'", key));
Console.WriteLine(string.Format("The value is '{0}'", value));
}
}
You can use the following code to call it with the default values
MethodInfo mi = typeof(Foo).GetMethod("Bar", BindingFlags.NonPublic | BindingFlags.Static);
ParameterInfo[] pis = mi.GetParameters();
object[] parameters = new object[pis.Length];
for (int i = 0; i < pis.Length; i++)
{
if (pis[i].IsOptional)
{
parameters[i] = pis[i].DefaultValue;
}
}
mi.Invoke(null, parameters);
If the method had some non-optional parameters, you will have to insert them into the parameters array before invoking the method.
E.g
private static void Bar(int number, string key = "undefined key", string value = "undefined")
Would require you to do
parameters[0] = "23"
Before invoking
Something i wrote for my unit tests:
/// <summary>
/// Attempts to execute a function and provide the result value against the provided source object even if it is private and/or static. Just make sure to provide the correct BindingFlags to correctly identify the function.
/// </summary>
/// <typeparam name="TReturn">The expected return type of the private method.</typeparam>
/// <param name="type">The object's Type that contains the private method.</param>
/// <param name="source">The object that contains the function to invoke. If looking for a static function, you can provide "null".</param>
/// <param name="methodName">The name of the private method to run.</param>
/// <param name="flags">Binding flags used to search for the function. Example: (BindingFlags.NonPublic | BindingFlags.Static) finds a private static method.</param>
/// <param name="output">The invoked function's return value.</param>
/// <param name="methodArgs">The arguments to pass into the private method.</param>
/// <returns>Returns true if function was found and invoked. False if function was not found.</returns>
private static bool TryInvokeMethod<TReturn>(Type type, object source, string methodName, BindingFlags flags, out TReturn output, params object[] methodArgs)
{
var method = type.GetMethod(methodName, flags);
if(method != null)
{
output = (TReturn)method.Invoke(source, methodArgs);
return true;
}
// Perform some recursion to walk the inheritance.
if(type.BaseType != null)
{
return TryInvokeMethod(type.BaseType, source, methodName, flags, out output, methodArgs);
}
output = default(TReturn);
return false;
}
Then call it like so to invoke a private static function:
var success = TryInvokeMethod(typeof(Foo), null, "MyPrivateStaticFunc", BindingFlags.NonPublic | BindingFlags.Static, out result, arg1ToPass);
Disclaimer: I use this for functions with a return value only. Attempting to execute a method with no return value will throw an exception.
I'm starting to work with dynamic objects in .Net and I can't figure out how to do something.
I have a class that inherits from DynamicObject, and I override the TryInvokeMember method.
e.g.
class MyCustomDynamicClass : DynamicObject
{
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
// I want to know here the type of the generic argument
}
}
And inside that method I want to know the type (if any) of the generic arguments in the invocation.
e.g.
If I invoke the following code, I want to get the value of System.Boolean and System.Int32 inside the overrided method of my dynamic object
dynamic myObject = new MyCustomDynamicClass();
myObject.SomeMethod<bool>("arg");
myObject.SomeOtherMethod<int>("arg");
Currently if I place a breakpoint inside the overrided method I can get the name of the method being invoked ("SomeMethod" and "SomeOtherMethod", and also the values of the arguments, but not the generic types).
How can I get these values?
Thanks!
Actually I looked through the hierarchy of the binder and found a property with the needed values in the internal fields of the object.
The problem is that the property isn't exposed because it uses C#-specific code/classes, therefore the properties must be accessed using Reflection.
I found the code in this japanese blog: http://neue.cc/category/programming (I don't read any japanese, therefore I'm not sure if the author actually describes this same issue
Here's the snippet:
var csharpBinder = binder.GetType().GetInterface("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder");
var typeArgs = (csharpBinder.GetProperty("TypeArguments").GetValue(binder, null) as IList<Type>);
typeArgs is a list containing the types of the generic arguments used when invoking the method.
Hope this helps someone else.
A bit of googling and I have quite generic solution for .NET and Mono:
/// <summary>Framework detection and specific implementations.</summary>
public static class FrameworkTools
{
private static bool _isMono = Type.GetType("Mono.Runtime") != null;
private static Func<InvokeMemberBinder, IList<Type>> _frameworkTypeArgumentsGetter = null;
/// <summary>Gets a value indicating whether application is running under mono runtime.</summary>
public static bool IsMono { get { return _isMono; } }
static FrameworkTools()
{
_frameworkTypeArgumentsGetter = CreateTypeArgumentsGetter();
}
private static Func<InvokeMemberBinder, IList<Type>> CreateTypeArgumentsGetter()
{
if (IsMono)
{
var binderType = typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly.GetType("Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder");
if (binderType != null)
{
ParameterExpression param = Expression.Parameter(typeof(InvokeMemberBinder), "o");
return Expression.Lambda<Func<InvokeMemberBinder, IList<Type>>>(
Expression.TypeAs(
Expression.Field(
Expression.TypeAs(param, binderType), "typeArguments"),
typeof(IList<Type>)), param).Compile();
}
}
else
{
var inter = typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly.GetType("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder");
if (inter != null)
{
var prop = inter.GetProperty("TypeArguments");
if (!prop.CanRead)
return null;
var objParm = Expression.Parameter(typeof(InvokeMemberBinder), "o");
return Expression.Lambda<Func<InvokeMemberBinder, IList<Type>>>(
Expression.TypeAs(
Expression.Property(
Expression.TypeAs(objParm, inter),
prop.Name),
typeof(IList<Type>)), objParm).Compile();
}
}
return null;
}
/// <summary>Extension method allowing to easyly extract generic type arguments from <see cref="InvokeMemberBinder"/>.</summary>
/// <param name="binder">Binder from which get type arguments.</param>
/// <returns>List of types passed as generic parameters.</returns>
public static IList<Type> GetGenericTypeArguments(this InvokeMemberBinder binder)
{
// First try to use delegate if exist
if (_frameworkTypeArgumentsGetter != null)
return _frameworkTypeArgumentsGetter(binder);
if (_isMono)
{
// In mono this is trivial.
// First we get field info.
var field = binder.GetType().GetField("typeArguments", BindingFlags.Instance |
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
// If this was a success get and return it's value
if (field != null)
return field.GetValue(binder) as IList<Type>;
}
else
{
// In this case, we need more aerobic :D
// First, get the interface
var inter = binder.GetType().GetInterface("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder");
if (inter != null)
{
// Now get property.
var prop = inter.GetProperty("TypeArguments");
// If we have a property, return it's value
if (prop != null)
return prop.GetValue(binder, null) as IList<Type>;
}
}
// Sadly return null if failed.
return null;
}
}
Have fun. By the way Impromptu is cool, but I can't use it.
The open source framework Dynamitey can call properties that internal/protected/private using the DLR and thus works with Silverlight. But it get's a little tricky with interface explicit members as you have to use the actual full name of the member on the the type, rather than the interface member name. So you can do:
var typeArgs = Dynamic.InvokeGet(binder, "Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder.TypeArguments")
as IList<Type>;
This question already has answers here:
Get a generic method without using GetMethods
(10 answers)
Closed 9 years ago.
I'm trying to retrieve MethodInfo for Where method of Enumerable type:
typeof (Enumerable).GetMethod("Where", new Type[] {
typeof(IEnumerable<>),
typeof(Func<,>)
})
but get null. What am I doing wrong?
That previous answer works for some cases, however:
It doesn't handle nested generic types, such as a parameter type of Action<IEnumerable<T>>. It will treat all Action<> as matches, for example, string.Concat(IEnumerable<string>) and string.Concat<T>(IEnumerable<T>) will both match if searching for "Concat" with type IEnumerable<> on the string type. What is really desirable is handling nested generic types recursively, while treating all generic parameters as matching each other regardless of name while NOT matching concrete types.
It returns the first method matched rather than throwing an exception if the result is ambiguous, like type.GetMethod() does. So, you might get the method you wanted if you're lucky, or you might not.
Sometimes it will be necessary to specify BindingFlags in order to avoid ambiguity, such as when a derived class method 'hides' a base class method. You normally want to find base class methods, but not in a specialized case where you know the method you're looking for is in the derived class. Or, you might know you're looking for a static vs instance method, public vs private, etc. and don't want to match if it's not exact.
It doesn't address another major fault with type.GetMethods(), in that it also doesn't search base interfaces for methods when looking for a method on an interface type. OK, maybe that's being picky, but it's another major flaw in GetMethods() that has been a problem for me.
Calling type.GetMethods() is inefficient, type.GetMember(name, MemberTypes.Method, ...) will return only methods with a matching name instead of ALL methods in the type.
As a final nit-pick, the name GetGenericMethod() could be misleading, since you might be trying to find a non-generic method that happens to have a type parameter somewhere in a parameter type due to a generic declaring type.
Here's a version that addresses all of those things, and can be used as a general-purpose replacement for the flawed GetMethod(). Note that two extension methods are provided, one with BindingFlags and one without (for convenience).
/// <summary>
/// Search for a method by name and parameter types.
/// Unlike GetMethod(), does 'loose' matching on generic
/// parameter types, and searches base interfaces.
/// </summary>
/// <exception cref="AmbiguousMatchException"/>
public static MethodInfo GetMethodExt( this Type thisType,
string name,
params Type[] parameterTypes)
{
return GetMethodExt(thisType,
name,
BindingFlags.Instance
| BindingFlags.Static
| BindingFlags.Public
| BindingFlags.NonPublic
| BindingFlags.FlattenHierarchy,
parameterTypes);
}
/// <summary>
/// Search for a method by name, parameter types, and binding flags.
/// Unlike GetMethod(), does 'loose' matching on generic
/// parameter types, and searches base interfaces.
/// </summary>
/// <exception cref="AmbiguousMatchException"/>
public static MethodInfo GetMethodExt( this Type thisType,
string name,
BindingFlags bindingFlags,
params Type[] parameterTypes)
{
MethodInfo matchingMethod = null;
// Check all methods with the specified name, including in base classes
GetMethodExt(ref matchingMethod, thisType, name, bindingFlags, parameterTypes);
// If we're searching an interface, we have to manually search base interfaces
if (matchingMethod == null && thisType.IsInterface)
{
foreach (Type interfaceType in thisType.GetInterfaces())
GetMethodExt(ref matchingMethod,
interfaceType,
name,
bindingFlags,
parameterTypes);
}
return matchingMethod;
}
private static void GetMethodExt( ref MethodInfo matchingMethod,
Type type,
string name,
BindingFlags bindingFlags,
params Type[] parameterTypes)
{
// Check all methods with the specified name, including in base classes
foreach (MethodInfo methodInfo in type.GetMember(name,
MemberTypes.Method,
bindingFlags))
{
// Check that the parameter counts and types match,
// with 'loose' matching on generic parameters
ParameterInfo[] parameterInfos = methodInfo.GetParameters();
if (parameterInfos.Length == parameterTypes.Length)
{
int i = 0;
for (; i < parameterInfos.Length; ++i)
{
if (!parameterInfos[i].ParameterType
.IsSimilarType(parameterTypes[i]))
break;
}
if (i == parameterInfos.Length)
{
if (matchingMethod == null)
matchingMethod = methodInfo;
else
throw new AmbiguousMatchException(
"More than one matching method found!");
}
}
}
}
/// <summary>
/// Special type used to match any generic parameter type in GetMethodExt().
/// </summary>
public class T
{ }
/// <summary>
/// Determines if the two types are either identical, or are both generic
/// parameters or generic types with generic parameters in the same
/// locations (generic parameters match any other generic paramter,
/// but NOT concrete types).
/// </summary>
private static bool IsSimilarType(this Type thisType, Type type)
{
// Ignore any 'ref' types
if (thisType.IsByRef)
thisType = thisType.GetElementType();
if (type.IsByRef)
type = type.GetElementType();
// Handle array types
if (thisType.IsArray && type.IsArray)
return thisType.GetElementType().IsSimilarType(type.GetElementType());
// If the types are identical, or they're both generic parameters
// or the special 'T' type, treat as a match
if (thisType == type || ((thisType.IsGenericParameter || thisType == typeof(T))
&& (type.IsGenericParameter || type == typeof(T))))
return true;
// Handle any generic arguments
if (thisType.IsGenericType && type.IsGenericType)
{
Type[] thisArguments = thisType.GetGenericArguments();
Type[] arguments = type.GetGenericArguments();
if (thisArguments.Length == arguments.Length)
{
for (int i = 0; i < thisArguments.Length; ++i)
{
if (!thisArguments[i].IsSimilarType(arguments[i]))
return false;
}
return true;
}
}
return false;
}
Note that the IsSimilarType(Type) extension method can be made public and might be useful on its own. I know, the name isn't great - you're welcome to come up with a better one, but it might get really long to explain what it does. Also, I added yet another improvement by checking for 'ref' and array types (refs are ignored for matching, but arrays dimensions must match).
So, that's how Microsoft should have done it. It's really not that hard.
Yeah, I know, you can shorten some of that logic using Linq, but I'm not a huge fan of Linq in low-level routines like this, and also not unless the Linq is about as easy to follow as the original code, which is often NOT the case, IMO.
If you love Linq, and you must, you can replace the inner-most part of IsSimilarType() with this (turns 8 lines into 1):
if (thisArguments.Length == arguments.Length)
return !thisArguments.Where((t, i) => !t.IsSimilarType(arguments[i])).Any();
One last thing: If you're looking for a generic method with a generic parameter, such as Method<T>(T, T[]), you'll have to find a Type which is a generic parameter (IsGenericParameter == true) to pass in for the parameter type (any one will do, because of the 'wildcard' matching). However, you can't just do new Type() - you have to find a real one (or build one with TypeBuilder). To make this easier, I added the public class T declaration, and added logic to IsSimilarType() to check for it and match any generic parameter. If you need a T[], just use T.MakeArrayType(1).
Unfortunately, generics are not well-supported in .NET Reflection. In this particular case, you'll need to call GetMethods and then filter the result set for the method you're looking for. An extension method like the following should do the trick.
public static class TypeExtensions
{
private class SimpleTypeComparer : IEqualityComparer<Type>
{
public bool Equals(Type x, Type y)
{
return x.Assembly == y.Assembly &&
x.Namespace == y.Namespace &&
x.Name == y.Name;
}
public int GetHashCode(Type obj)
{
throw new NotImplementedException();
}
}
public static MethodInfo GetGenericMethod(this Type type, string name, Type[] parameterTypes)
{
var methods = type.GetMethods();
foreach (var method in methods.Where(m => m.Name == name))
{
var methodParameterTypes = method.GetParameters().Select(p => p.ParameterType).ToArray();
if (methodParameterTypes.SequenceEqual(parameterTypes, new SimpleTypeComparer()))
{
return method;
}
}
return null;
}
}
With this in hand the following code will work:
typeof(Enumerable).GetGenericMethod("Where", new Type[] { typeof(IEnumerable<>), typeof(Func<,>) });
In my reflection code i hit a problem with my generic section of code. Specifically when i use a string.
var oVal = (object)"Test";
var oType = oVal.GetType();
var sz = Activator.CreateInstance(oType, oVal);
Exception
An unhandled exception of type 'System.MissingMethodException' occurred in mscorlib.dll
Additional information: Constructor on type 'System.String' not found.
I tried this for testing purposes and it occurs in this single liner too
var sz = Activator.CreateInstance("".GetType(), "Test");
originally i wrote
var sz = Activator.CreateInstance("".GetType());
but i get this error
Additional information: No parameterless constructor defined for this object.
How do i create a string using reflection?
Keep in mind that the string class is immutable. It cannot be changed after it is created. That explains why it doesn't have a parameterless constructor, it could never generate a useful string object other than an empty string. That's already available in the C# language, it is "".
Same reasoning applies for a string(String) constructor. There is no point in duplicating a string, the string you'd pass to the constructor is already a perfectly good instance of the string.
So fix your problem by testing for the string case:
var oType = oVal.GetType();
if (oType == typeof(string)) return oVal as string;
else return Activator.CreateInstance(oType, oVal);
You are trying to do this :
var sz = new string();
Try to compile it, you will understand your error.
You may try :
var sz = Activator.CreateInstance(typeof(string), new object[] {"value".ToCharArray()});
But it looks useless, you should directly use value...
It looks like you're trying to call a constructor which just takes a string - and there isn't such a constructor. If you've already got a string, why are you trying to create a new one? (When you didn't provide any further arguments, you were trying to call a parameterless constructor - which again, doesn't exist.)
Note that typeof(string) is a simpler way to get a reference to the string type.
Could you give us more information about the bigger picture of what you're trying to do?
String actually has no constructor that takes a string as input. There is a constructor that takes a char array so this should work:
var sz = Activator.CreateInstance ("".GetType (), "Test".ToCharArray ());
This is what I use in my projects. As far as needing to create an instantiation of a type of object and not knowing at design time, is rather normal for me. Perhaps you are cycling through object properties and you want to instantiate all of them dynamically. I have many times needed to create then assign values to non instantiated POCO objects... with the below code you can use a string value stored in the DB to instantiate an object as well or instantiate an object stored in a library that is referencing your library - so you can bypass circular reference errors as well... Hope it helps.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
/// <summary>
/// Instantiates an object. Must pass PropertyType.AssemblyQualifiedName for factory to operate
/// returns instantiated object
/// </summary>
/// <param name="typeName"></param>
/// <returns></returns>
public static object Create(string typeAssemblyQualifiedName)
{
// resolve the type
Type targetType = ResolveType(typeAssemblyQualifiedName);
if (targetType == null)
throw new ArgumentException("Unable to resolve object type: " + typeAssemblyQualifiedName);
return Create(targetType);
}
/// <summary>
/// create by type of T
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T Create<T>()
{
Type targetType = typeof(T);
return (T)Create(targetType);
}
/// <summary>
/// general object creation
/// </summary>
/// <param name="targetType"></param>
/// <returns></returns>
public static object Create(Type targetType)
{
//string test first - it has no parameterless constructor
if (Type.GetTypeCode(targetType) == TypeCode.String)
return string.Empty;
// get the default constructor and instantiate
Type[] types = new Type[0];
ConstructorInfo info = targetType.GetConstructor(types);
object targetObject = null;
if (info == null) //must not have found the constructor
if (targetType.BaseType.UnderlyingSystemType.FullName.Contains("Enum"))
targetObject = Activator.CreateInstance(targetType);
else
throw new ArgumentException("Unable to instantiate type: " + targetType.AssemblyQualifiedName + " - Constructor not found");
else
targetObject = info.Invoke(null);
if (targetObject == null)
throw new ArgumentException("Unable to instantiate type: " + targetType.AssemblyQualifiedName + " - Unknown Error");
return targetObject;
}
/// <summary>
/// Loads the assembly of an object. Must pass PropertyType.AssemblyQualifiedName for factory to operate
/// Returns the object type.
/// </summary>
/// <param name="typeString"></param>
/// <returns></returns>
public static Type ResolveType(string typeAssemblyQualifiedName)
{
int commaIndex = typeAssemblyQualifiedName.IndexOf(",");
string className = typeAssemblyQualifiedName.Substring(0, commaIndex).Trim();
string assemblyName = typeAssemblyQualifiedName.Substring(commaIndex + 1).Trim();
if (className.Contains("[]"))
className.Remove(className.IndexOf("[]"), 2);
// Get the assembly containing the handler
Assembly assembly = null;
try
{
assembly = Assembly.Load(assemblyName);
}
catch
{
try
{
assembly = Assembly.LoadWithPartialName(assemblyName);//yes yes this is obsolete but it is only a backup call
}
catch
{
throw new ArgumentException("Can't load assembly " + assemblyName);
}
}
// Get the handler
return assembly.GetType(className, false, false);
}