I've got a legacy vb.net dll referenced in my c# project.
calling the various methods no problem, but I need to be able to display a form from the dll, so users can pick the right line from a database response.
Assembly assembly = Assembly.LoadFile("FMSValidation.dll");
produces no error, but
Type type = assembly.GetType (FMSValidation.CreditorDetails );
tells me 'CreditorDetails' is a type, which is not valid in the context.
assembly.GetType does not accept an actual type. It accepts a string:
Type type = assembly.GetType("FMSValidation.CreditorDetails");
It wouldn't make sense for assembly.GetType to be able to take a type, since at that point you already have a type.
Once you have a type, you can create an instance of it with the activator class:
var form = (System.Windows.Forms.Form)Activator.CreateInstance(type);
form.ShowDialog();
If CreditorDetails requires any constructor arguments, use an overload of CreateInstance that accepts the array of arguments.
It seems like the compiler knows FMSValidation.CreditorDetails is a type - so I wonder why you are dynamically loading the assembly and trying to use GetType at all. You should just be able to add a reference to the assembly and use its types like you would any other, like new FMSValidation.CreditorDetails().
FMSValidation.CreditorDetails is a type, but it is not an actual Type object. If you want an actual type object, and you can write the name of the type in your source code (ie. it's not in a string variable or something) then you would use typeof(FMSValidation.CreditorDetails) instead of assembly.GetType.
Related
I am trying to load the old version of farpoint dll in my project by using below code
System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFile(#"FarPoint.Web.Spread.dll");
System.Type MyDLLFormType = assembly.GetType("FarPoint.Web.Spread.FpSpread");
var c = Activator.CreateInstance(MyDLLFormType);
The problem is after the instance is created, all the available methods of farpoint are not available
[ for example - if i create the object directly the methods like saveExcel or savechanges are available with the instance]
FpSpread fpProxyObject = new FpSpread();
fpProxyObject.SaveExcel();
They are available, just not at compile time. Activator.CreateInstance() returns an object. You could of course cast the object:
var c = Activator.CreateInstance(...)
FpSpread fpProxyObject = (FpSpread)c;
But that would probably beat the whole purpose of using reflection to create the instance.
You can access all members of the result object by using reflection, ie:
MethodInfo saveExcelMethod = c.GetType().GetMethod("SaveExcel");
if (saveExcelMethod == null) throw new ApplicationException("Incorrect version of FarPoint");
saveExcelMethod.Invoke(c);
Intellisense is not working, because, as said #C.Evenhuis, Activator.CreateInstance returns object, so you should cast it to appropriate type.
If type is not known at compile time, but you have access to a code-base, you could try to add interface for it, and implement it by your class. Then cast object to that interface and use it. (I don't know your purpose, but interface could be treated as a contract for all the types, that you will load dynamically).
If type is not known at compile time and you have no access to a code-base, you could use reflection for method invocation or use dynamic instead.
dynamic c = Activator.CreateInstance(MyDLLFormType);
c.SaveExcel(); // this method invocation will be bound in runtime.
By the way be carefull, while using Assembly.LoadFile. You may get more details from this article.
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'm using this method to create the object I want to.
The constructor of the object is successfully called.
Now, I want to call a method via reflection, but as I found out, I need to know the type. And when I do something like
Type type = Type.GetType(this.typeName);
type is null.
So, what I need to know is: How do I get the type of an assembly loaded in a new AppDomain?
You need to use the full assembly qualified name, so you can recreate it with Type.GetType()
this.typeName = typeof(MyClass).AssemblyQualifiedName;
Without this, the executing assembly will be searched for the type which doesn't always contain your type.
System.type type object is an object by itself and has a type object pointer member in it, and it’s member refers to itself because the System.Type type object is itself an “instance” of a type object. And System.Object’s GetType method returns the address stored in the specified object’s type object pointer member. In other words the GetType method returns a pointer to an object’s type object, and this is how you can determine the true type of any object in the system.
Use System.Reflection.AssemblyName is an utility class which gives you complete details of an assembly's unique identity in full. Use GetType method of this Class to know the type of the Assembly loaded.
http://msdn.microsoft.com/en-us/library/system.object.gettype.aspx
Here is how i solved the problem:
I created an interface, and used typeof(MyInterface) to work arround.
I hope this could help you.
In VB (ASP.NET)
Application("myapp")= Server.CreateObject("APP.Engine")
aa = Application("myapp").myMethod(2)
works.
In C# I tried
Application["myapp"]= Server.CreateObject("APP.Engine")
but
Application["myapp"].myMethod(2)
fails with
'object' does not contain a definition for 'myMethod'
How can I expose the public interface in C#?
If you have access to the defining type (i.e. not a raw COM object), you can simply cast:
((APP.Engine)Application["myapp"]).myMethod(2);
If you are using c# 4.0, you can do:
dymamic myApp = Application["myapp"];
myApp.myMethod(2);
Otherwise you will have to use dynamic method invocation using reflection and Type.InvokeMember(...)
You need to cast to the correct class first, like:
((APP.Engine)Application["myapp"]).myMethod(2)
Cast the result of Application["myapp"] to the correct type, like so:
((APP.Engine)Application["myapp"]).myMethod(2);
Other options include creating a local reference and using that instead.
This basically happens as C# is strongly typed language. When you call Application you are actually calling a collection of type Object. The collection is actually an array of Object. We take it as object because it will enable you to store almost anything to the collection.
Now Application["myapp"] will eventually return an object of System.Object type.
So you need to typecast the object to your type.
App.Engine obj = Application["myapp"] as App.Engine;
if(obj != null)
obj.myMethod(2);
The object obj is a reference to the actual type and the compiler will not throw any exception if you call myMethod(2).
Just remember one thing while converting code from VB to C# is, C# is the strongly typed language and before you access any type, you will need to convert it. However same wasn't required in VB.
So for this example you would need to use App.Engine for type conversion.
((APP.Engine)Application["myapp"]).myMethod(2)
I want to create an instance of value types like System.String, System.Boolean, System.Int32, etc. I get qualified names of types like System.String or MyNamespace.Employee and I have to create an instance and return back. I use Activator.CreateInstance and FormatterServices.GetUninitializedObject to create instances. But it fails in case of value types. I cannot hard code the logic in case of value types. I need a generic way of creating instances of both value types and reference types.
What exactly is it you are trying to do? FormatterServices.GetUninitializedObject is used mainly by serialization code; outside of that you shouldn't really use it. It sounds like you might just need something like TypeConverter, i.e. (for these types)
TypeConverter tc = TypeDescriptor.GetConverter(someType);
object obj = tc.ConvertFromString(s);
What exactly is failing? I tried the following code to see if there is a problem with value types:
var instance = Activator.CreateInstance(typeof(Int32));
It gives me an Int32 instance set to 0.
Where exactly is your code failing? Otherwise I would say the problem lies with the way you are loading the type, not the way you are creating the instance.
For BCL Value Types (and when using Strings to describe types) ensure you are not using C# keywords and ensure the Type is fully qualified with namespace. For example, C# int is successfully created this way with Activator.CreateInstance(..)
object num = Activator.CreateInstance(Type.GetType("System.Int32"));
You will get failed attempts if you try to use language-specific aliases like "int" or short forms like "Int32".
This works for me:
int x = (int)Activator.CreateInstance(typeof (Int32), true);