15

I have a set of classes, each one is a different strategy to do the same work.

namespace BigCorp.SuperApp
{
    public class BaseClass { }
    public class ClassA : BaseClass { }
    public class ClassB : BaseClass { }
}

The choice of which strategy to use is configurable. I want to configure only the class name 'ClassB' instead of the full type name 'BigCorp.SuperApp.ClassB' in the app.config file.

<appConfig>
   <SuperAppConfig>
      <Handler name="ClassB" />
   </SuperAppConfig>
</appConfig>

However, the reflection calls fail because they expect the full type name, particularly

Type t = Type.GetType("ClassB"); // results in t == null
BaseClass c = Activator.CreateInstance(t) as BaseClass; // fails

How can I get this to work while configuring only the class name? Concatenate the namespace to the class name for full type name? Is there another reflection call that works?

If you think this is useless and I should expect the configuration to contain the full type name, I am open to that solution! Just provide rationale to convince me.

(I will not be loading a type from outside this assembly/namespace)

1
  • I could just use an IoC container, deal with long names, and get object creation done for me! Commented Dec 1, 2009 at 14:02

5 Answers 5

18

Either use the assembly-qualified-name, or get hold of the Assembly and use Assembly.GetType(name). In this case, since you want the types in the config file, assembly-qualified is a valid way to go - but since you know all your types are in the same assembly:

Assembly assembly = typeof(SomeKnownType).Assembly; // in the same assembly!
Type type = assembly.GetType(name); // full name - i.e. with namespace (perhaps concatenate)
object obj = Activator.CreateInstance(type);

The static Type.GetType(string) has probing rules that often cause confusion... it looks at the calling assembly, and a few system assemblies - but not all loaded assemblies.

Sign up to request clarification or add additional context in comments.

1 Comment

I have a service reference which I want to call using this, but it won't show up in the type list of the assembly (made from the class). Even though I can create an object of the reference by calling the constructor hardcode.
6

Since you know all classes will be coming from the same namespace, configure it once and use that:

<appConfig>
   <SuperAppConfig handlerNamespace="BigCorp.SuperApp">
      <Handler class="ClassB" />
   </SuperAppConfig>
</appConfig>

Edit: I changed name to class to better denote the meaning of that attribute.

1 Comment

I appreciate the answers, code, and discussion of assembly loading. But I like Bryan's answer for the focus on configuration (since I can't get away from full type name).
5
(I will not be loading a type from outside this assembly/namespace)

because of the above line, it is safe to assume that you know what the namespace is. Couldn't you do something like:

Type t = Type.GetType("Namespace." + className); 
BaseClass c = Activator.CreateInstance(t) as BaseClass; 

If you expect to possibly be able to add additional strategy classes to be loaded in the future, perhaps via an additional assembly, you would need to fully qualify your class name. This is recommended anyway, since you would be able to provide enhanced extendability for your application.

1 Comment

That actually depends where that code is (and how you interpret "from outside" - i.e. is that the class? or the caller?). Without an assembly-qualified name, Type.GetType(string) will only look at the current assembly and a few system assemblies. It won't find types in random referenced dlls.
2

I'm going with the full type name in the application configuration. Below is a slightly more complete, but still trivial example

<SuperAppConfig>
   <ObjectConfig provider="BigCorp.SuperApp.ClassA">
      <add name="one" />
      <add name="two" />
   </ObjectConfig>
</SuperAppConfig>

And the factory class that actually creates this

private static Assembly a = typeof(IFactoryObject).Assembly;
public static IFactoryObject CreateObject(String providerName)
{
    Type t = a.GetType(providerName)
    IFactoryObject o = Activator.CreateInstance(t) as IFactoryObject;
    return o;
}

Comments

1
BaseClass c = Activator.CreateInstance(t) as BaseClass; // fails

Might also result from the fact, that CreateInstance does not return an instance of BaseClass, rather than an instance of BaseClass wrapped into an ObjectHandle.

Cast into your BaseClass after you used the UnWrap method.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.