2

I'm not sure if this is possible, and I'm quite new to using assemblies in C#.NET.

What I would like to do is to create an instance of a class when supplied the string name of that class. Something like this:

using MyAssembly;

namespace MyNameSpace
{
     Class MyClass
     {
          int MyValue1;
          int MyValue2;

          public MyClass(string myTypeName)
          {
               foreach(Type type in MyAssembly)
               {
                    if((string)type == myTypeName)
                    {
                         //create a new instance of the type
                    }
               }
               AssignInitialValues(//the type created above)
          }

          //Here I use an abstract type which the type above inherits from
          private void AssignInitialValues(AbstractType myClass)
          {
               this.value1 = myClass.value1;
               this.value2 = myClass.value2;
          }
      }
 }

Obviously you cannot compare strings to types but it illustrates what I'm trying to do: create a type found in a different assembly from a supplied string.

Any thoughts?


EDIT:

After attempting:

var myObject = (AbstractType) Activator.CreateInstance(null, myTypeName);
AssignInitialValues(myObject);

I get a number of errors:

  • Inconsistent accessibility: parameter type 'MyAssembly.AbstractType' is less accessible than method 'MyNameSpace.MyClass.AssignInitialValues(MyAssembly.AstractType)'
  • 'MyAssembly.AstractType' is inaccessible due to it's protection level
  • The type or namespace name 'MyAssembly' could not be found (are you missing a using directive or an assembly reference?)
  • The type or namespace name 'AbstractType' could not be found (are you missing a using directive or an assembly reference?)

Not exactly sure why it can't find the assembly; I've added a reference to the assembly and I use a Using Directive for the namespace in the assembly. As for the protection level, it's calling classes (or rather the constructors of classes) which can only be public.

Any clues on where the problem is?


UPDATE:

After looking through several articles on SO I came across this: https://stackoverflow.com/a/1632609/360627 Making the AbstractTypeclass public solved the issue of inconsistent accessibility.

The new compiler error is this:

Cannot convert type 'System.Runtime.Remoting.ObjectHandle' to 'MyAssembly.AbstractType'

The line it references is this one:

var myObject = (AbstractType) Activator.CreateInstance(null, myTypeName);

Using .Unwrap() get's me past this error and I think it's the right way to do it (uncertain). However, when running the program I then get a TypeLoadException when this code is called.

TypeLoadException: Could not load type ‘AbstractType’ from assembly ‘MyNameSpace'...

Right away I can spot that the type its looking for is correct but the assembly it's looking in is wrong. Looking up the Activator.CreateInstance(String, String) method revealed that the null as the first argument means that the method will look in the executing assembly. This is contrary to the required behavior as in the original post.

I've tried using MyAssembly as the first argument but this produces the error:

'MyAssembly' is a 'namespace' but is used like a 'variable'

I think that this is caused by MyAssembly not being a string. However if I try 'MyAssembly' I get the following compiler errors:

  • Too many characters in character literal
  • The best overloaded method match for 'System.Activator.CreateInstance(System.ActivationContext, string[])' has some invalid arguments
  • Argument 1: cannot convert from 'char' to 'System.ActivationContext'
  • Argument 2: cannot convert from 'string' to 'string[]'

Seems to me like it's trying to use the wrong overload.

Any thoughts on how to fix this?

5
  • Dupe: stackoverflow.com/q/7398147/422353 Commented Sep 15, 2012 at 0:22
  • @madth3: That actually doesn't answer my question because I get errors when I attempt to do that. See my comment on the answer below. Commented Sep 15, 2012 at 0:30
  • Ah, you might have said that and then we could work starting from there. Commented Sep 15, 2012 at 0:32
  • I see; I'll remember to mention what I've looked at and tried already next time I have a problem. Commented Sep 15, 2012 at 0:36
  • Hi Arcadian, now that your post is reopened, you should remove your answer from the question body and paste it below as an answer. Good luck! :) Commented Sep 16, 2012 at 22:01

3 Answers 3

8

If you have the fully qualified name of your type you don't need this foreach loop at all:

var myObject = (SomeBaseType) Activator.CreateInstance(null, myTypeName);
Sign up to request clarification or add additional context in comments.

1 Comment

When I try this I get an error saying that the parameter for AssignInitialValues is less accessible than the method itself. I don't see how that can be true since the parameter is just a class (which can't be private).
6

There are many ways to accomplish your need. Not the best performance :

Activator.CreateInstance(null, myTypeName);

You can also working with this:

var ci = Type.GetType(myTypeName).GetConstructor(Type.EmptyTypes);
var myTypeInstance = ci.Invoke(new object[]{})

1 Comment

Using your more efficient answer gets me a runtime exception: nullReferenceException. I believe, that like the other answer, this is caused by the code looking in the executing assembly and not MyAssembly.
4

Okay so this is the answer. I've tested it using real code and it works. I'm not sure if it's the best way or the most efficient way. I've upvoted the other two answers because they helped me get onto the right track but here is the full answer.

using MyAssembly;

namespace MyNameSpace
{
     Class MyClass
     {
          int MyValue1;
          int MyValue2;

          public MyClass(string myTypeName)
          {
               string assemblyName = Assembly.GetAssembly(typeof(AbstractType)).ToString();
               AbstractType selectedClass = (AbstractType)Activator.CreateInstance(assemblyName, myTypeName).Unwrap();
               AssignInitialValues(selectedClass);
          }

          private void AssignInitialValues(AbstractType myClass)
          {
               this.value1 = myClass.value1;
               this.value2 = myClass.value2;
          }
      }
 }

Took me three days of googling, searching through SO and MSDN but there it is. Note that when instantiating a class with Activator.CreateInstance(String, String) the assembly name (first parameter) must be the full assembly name not just the name of the .dll (or .exe).

The assembly name can be retrieved by using string assemblyName = Assembly.GetAssembly(typeof(AbstractType)).ToString(); where AbstractType can be replaced by a type you know to be contained and defined in the assembly.

The type name (second parameter) must be the fully qualified name, not just the class name.

1 Comment

When you refer to a type through a string, you must always use the fully qualified name (ie with namespace), and if the type is not in the assembly where the method is running (or in the executing assembly?), you must also specify the assembly name. So basically, you should always provide the assembly qualified name (see Type.AssemblyQualifiedName) when doing Activator.CreateInstance or Type.GetType. Else .Net won't be able to find your type.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.