Question
In C#, you may not always know an object's type at compile time, but you may still need to create an instance of that type at runtime.
How can you create a new object instance when all you have is a Type?
For example, the goal is to create an instance dynamically from something like:
Type type = /* some runtime type */;
and then produce a new object of that type.
Short Answer
By the end of this page, you will understand how to create objects dynamically in C# when you only have a Type at runtime. You will learn the most common approach using Activator.CreateInstance, how constructors affect object creation, when reflection is useful, and what mistakes to avoid when instantiating types dynamically.
Concept
In normal C# code, object creation usually happens with the new keyword:
var user = new User();
That works when the type is known at compile time. But sometimes a program discovers the type later, while it is running. This happens in scenarios like:
- plugin systems
- dependency injection containers
- serializers
- configuration-driven object creation
- test frameworks
When all you have is a Type object, you cannot write:
new type(); // invalid
because new requires a compile-time type name, not a runtime Type value.
This is where Activator.CreateInstance becomes useful. It lets you ask the runtime to create an object from a Type.
object instance = Activator.CreateInstance(type);
This creates a new instance of the specified type, usually by calling its parameterless constructor.
Why this matters:
- It allows flexible, extensible programs.
- It supports runtime discovery of classes.
- It is a core part of reflection-based programming.
However, dynamic creation comes with trade-offs:
- less compile-time safety
- possible runtime errors if constructors do not match
- often slower than direct
new
So it is powerful, but should be used intentionally.
Mental Model
Think of Type as a blueprint label, not the actual building.
new User()means: "Build me a house from theUserblueprint I already know."Type type = ...means: "Here is a label that tells you which blueprint to use, but you only find out at runtime."Activator.CreateInstance(type)means: "Use this blueprint label and build one instance now."
So Type tells you what something is, and Activator.CreateInstance is the worker that actually builds it.
Syntax and Examples
Basic syntax
object instance = Activator.CreateInstance(type);
This returns an object, because the compiler may not know the exact type.
Example with a parameterless constructor
using System;
class Person
{
public string Name { get; set; }
}
class Program
{
static void Main()
{
Type type = typeof(Person);
object instance = Activator.CreateInstance(type);
Person person = (Person)instance;
person.Name = "Ava";
Console.WriteLine(person.Name);
}
}
What this does
typeof(Person)gets the runtimeType.Activator.CreateInstance(type)creates a newPerson.- The result is returned as
object. - You cast it back to
Personif needed.
Example with constructor arguments
If the type does not have a parameterless constructor, you can pass arguments:
using System;
class Person
{
public string Name { get; }
public Person(string name)
{
Name = name;
}
}
class Program
{
static void Main()
{
Type type = typeof(Person);
object instance = Activator.CreateInstance(type, "Liam");
Person person = (Person)instance;
Console.WriteLine(person.Name);
}
}
The runtime looks for a constructor that matches the provided arguments.
Generic version
If the type is known in generic code, you can use:
T item = Activator.CreateInstance<T>();
This is useful in generic methods when T is the type parameter.
using System;
class Program
{
static T Create<T>()
{
return Activator.CreateInstance<T>();
}
}
This still depends on the runtime being able to construct T.
Step by Step Execution
Consider this example:
using System;
class Message
{
public string Text { get; set; } = "Hello";
}
class Program
{
static void Main()
{
Type type = typeof(Message);
object instance = Activator.CreateInstance(type);
Message message = (Message)instance;
Console.WriteLine(message.Text);
}
}
Step by step
-
Type type = typeof(Message);- The program gets metadata describing the
Messageclass. - No object is created yet.
- The program gets metadata describing the
-
object instance = Activator.CreateInstance(type);- The runtime checks the
Messagetype. - It finds a usable parameterless constructor.
- It creates a new
Messageobject. - The result is stored as
object.
- The runtime checks the
-
Message message = (Message)instance;- The code casts the general
objectreference back toMessage. - Now you can access
Messagemembers directly.
- The code casts the general
-
Console.WriteLine(message.Text);- The
Textproperty value is printed. - Output:
- The
Hello
Key idea
Type gives the runtime enough information to create the object, but the compiler still treats the result as object unless you cast it or work with a common interface or base class.
Real World Use Cases
Plugin systems
An app may load class names from assemblies and create plugin objects dynamically.
Type pluginType = loadedAssembly.GetType("MyApp.Plugins.CsvExporter");
object plugin = Activator.CreateInstance(pluginType);
Configuration-based services
A configuration file may specify which implementation to use.
EmailSenderSmsSenderPushNotificationSender
The application resolves the type at runtime and creates it.
Testing frameworks
Test runners often discover test classes through reflection and instantiate them automatically.
Serialization and mapping tools
Libraries may create objects before populating their properties from JSON, XML, or database records.
Command or job processors
A background worker may discover a job type from a queue message and instantiate the appropriate handler.
Real Codebase Usage
In real projects, developers usually combine runtime object creation with safer design patterns.
Common patterns
Create via interface or base class
Instead of using the created object as plain object, cast to a known abstraction:
IPlugin plugin = (IPlugin)Activator.CreateInstance(type);
plugin.Run();
This makes the rest of the code cleaner and safer.
Guard clauses before creation
Real code often validates the type first:
if (type == null)
throw new ArgumentNullException(nameof(type));
if (type.IsAbstract || type.IsInterface)
throw new InvalidOperationException("Type cannot be instantiated.");
Constructor matching
If arguments are needed, code ensures the right constructor exists.
object service = Activator.CreateInstance(type, connectionString);
Error handling
Because dynamic creation can fail at runtime, developers often wrap it:
try
{
return Activator.CreateInstance(type);
}
catch (Exception ex)
{
throw new InvalidOperationException($"Could not create instance of {type.FullName}", ex);
}
Factories over direct reflection
In larger codebases, teams often hide reflection behind a factory method or service. That keeps the rest of the app simple.
public object Create(Type type)
{
return Activator.CreateInstance(type);
}
This is easier to test and replace later.
Common Mistakes
1. Trying to use new with a Type
Broken code:
Type type = typeof(string);
// var x = new type(); // invalid
Why it fails:
newneeds a real type name at compile time.typeis just a variable holding metadata.
Use this instead:
object x = Activator.CreateInstance(type);
2. Assuming every type has a parameterless constructor
Broken code:
class Person
{
public Person(string name) { }
}
Type type = typeof(Person);
object instance = Activator.CreateInstance(type); // fails
Fix:
object instance = Activator.CreateInstance(type, "Mia");
3. Trying to instantiate interfaces or abstract classes
Broken code:
Type type = typeof(IDisposable);
object instance = Activator.CreateInstance(type); // fails
Fix:
- Use a concrete class.
- Check
type.IsInterfaceandtype.IsAbstractfirst.
4. Forgetting to cast the result
Activator.CreateInstance returns object.
object instance = Activator.CreateInstance(typeof(Person));
You must cast it if you need specific members:
Person person = (Person)instance;
5. Ignoring runtime exceptions
Dynamic creation can fail for many reasons:
- no matching constructor
- constructor throws an exception
- type cannot be instantiated
Always consider error handling when the type comes from outside your code.
6. Using reflection when a simpler design would work
Sometimes a dictionary of factory functions is simpler and safer than runtime reflection.
var factories = new Dictionary<string, Func<object>>
{
["person"] = () => new Person(),
["order"] = () => new Order()
};
If the set of types is known, this may be better than Activator.CreateInstance.
Comparisons
| Approach | When to use | Pros | Cons |
|---|---|---|---|
new MyClass() | Type known at compile time | Fast, safe, simple | Not dynamic |
Activator.CreateInstance(type) | Type known only at runtime | Flexible, built into .NET | Runtime errors possible |
Activator.CreateInstance(type, args) | Runtime type with constructor parameters | Can call matching constructors | More fragile if arguments do not match |
Generic new() constraint | Generic code with parameterless constructor | Compile-time safety | Only works for parameterless constructors |
| Factory method | Known set of types | Clear, testable, maintainable | Less dynamic |
Activator.CreateInstance vs generic new()
where T : new()
This allows:
T item = new T();
Comparison:
| Feature | Activator.CreateInstance | new() constraint |
|---|---|---|
Runtime Type support | Yes | No |
| Compile-time safety | Lower | Higher |
| Requires parameterless constructor | Usually, unless args are provided | Yes |
| Best for | Reflection and dynamic systems | Generic helper methods |
Cheat Sheet
Quick reference
Create an instance from a Type
object instance = Activator.CreateInstance(type);
Create with constructor arguments
object instance = Activator.CreateInstance(type, arg1, arg2);
Generic version
T instance = Activator.CreateInstance<T>();
Rules to remember
new SomeType()works only when the type is known at compile time.Activator.CreateInstanceworks when the type is known only at runtime.- The return type is usually
object. - Cast the result to a known interface, base class, or concrete type.
- The target type must be instantiable.
Common checks
if (type == null)
throw new ArgumentNullException(nameof(type));
if (type.IsInterface || type.IsAbstract)
throw new InvalidOperationException("Type cannot be instantiated.");
Common failure reasons
- no matching constructor
- abstract class
- interface
- constructor throws exception
- wrong argument list
Good practice
- Prefer interfaces or base classes after creation.
- Use factories if the possible types are known.
- Add error handling when the type comes from configuration, files, or external assemblies.
FAQ
How do I create an instance from a Type in C#?
Use Activator.CreateInstance(type). It asks the runtime to create an object for that Type.
Can I use new with a Type variable?
No. The new keyword requires a compile-time type name, not a runtime Type value.
What happens if the type has no default constructor?
You must pass matching constructor arguments, for example:
Activator.CreateInstance(type, "value")
Why does Activator.CreateInstance return object?
Because the compiler may not know the specific type in advance. You usually cast it to a known type, interface, or base class.
Can I create interfaces or abstract classes this way?
No. Interfaces and abstract classes cannot be instantiated directly.
Is Activator.CreateInstance slower than new?
Yes, generally it is slower because it uses runtime mechanisms. For most normal code, prefer new when possible.
When should I avoid dynamic instantiation?
Avoid it when the set of types is already known. In those cases, direct construction or factory methods are usually simpler and safer.
Mini Project
Description
Build a small runtime object factory in C#. The program should accept a Type, create an instance if possible, and print information about the created object. This demonstrates practical use of Activator.CreateInstance, type validation, and safe casting.
Goal
Create a reusable method that instantiates valid runtime types and rejects types that cannot be created.
Requirements
- Create at least two sample classes that can be instantiated.
- Add one type that cannot be instantiated directly, such as an abstract class or interface.
- Write a method that accepts a
Typeand returns a new object instance. - Validate the type before instantiating it.
- Print success or error messages for each test type.
Keep learning
Related questions
AddTransient vs AddScoped vs AddSingleton in ASP.NET Core Dependency Injection
Learn the differences between AddTransient, AddScoped, and AddSingleton in ASP.NET Core DI with examples and practical usage.
Best Way to Repeat a Character in C#: Building Repeated Strings Efficiently
Learn the best way to repeat a character in C#, compare StringBuilder, string concatenation, and simpler built-in options.
C# Access Modifiers and static: public, private, protected, and Defaults
Learn how C# public, private, protected, and default access control visibility, and how static differs from instance members.