Reputation: 123632
EDIT: changed Activator
, still doesn't work.
So I'm pretty (very) new to C# and I'm pretty sure this is a dupe, but I've looked through the previous questions and I still can't work out all the points.
I am trying to reduce code smell by replacing some repeated code with a map over a generic list. Specifically, I have code that looks like
var fooNode = node as IFoo;
var barNode = node as IBar;
var bazNode = node as IBaz;
...
if(fooNode != null)
return new FooThing();
if(barNode != null)
return new BarThing();
if(bazNode != null)
return new BazThing();
...
and I want to generalise it.
Here's my attempt:
var types = new Dictionary<Type, Type>
{
{typeof(IFoo), typeof(FooThing)},
{typeof(IBar), typeof(BarThing)},
...
}
foreach(var entry in types)
{
var castNode = node as entry.Key;
return Activator.CreateInstance(entry.Value);
}
Naturally, it doesn't work: The type or namespace name 'entry' could not be found (are you missing a using directive or an assembly reference?)
. Can you help? Is this sort of thing even possible in C#?
Upvotes: 2
Views: 576
Reputation: 487
Without understanding clearly your purpose for wanting to return different types from the same operation it will be hard to help. Maybe a little background information into the problem you are trying to solve??
I will assume that since you are attempting to return them interchangeably that fooThing, BartThing and BazThing have the same interface. So I am assuming the following:
public class FooThing : IMyOperations
{
}
public class BarThing : IMyOperations
{
}
public class BazThing : IMyOperations
{
}
You can define the relationship between the classes in another interface
public interface IMyChoice
{
public bool IsSelected { get; }
public IMyOperations GetWorker();
}
public class ChoiceFoo : IMyChoice
{
}
public class ChoiceBar : IMyChoice
{
}
public class ChoiceBaz : IMyChoice
{
}
Now you can say
foreach( var entry in choices)
{
if(entry.IsSelected)
{
return entry.GetWorker();
//Can't remember if i need to break after return..doubt it
}
}
Upvotes: 0
Reputation: 86729
How about this?
foreach(var entry in types)
{
if (node != null && entry.Key.IsAssignableFrom(node.GetType()))
{
return Activator.CreateInstance(entry.Value);
}
}
The problem is that you are confusing generic type parameters with runtime types and in particular the Type
class.
If you know what a type will be at compile time then you can use the generic Activator.CreateInstance<T>()
method to create an instance of the underlying object - you can use things like type parameters so that this line of code doesn't need to know what the type is, for example:
T CreateObject<T>()
{
return Activator.CreateInstance<T>();
}
However this just passes the buck. In order to call this method the value of the type parameter T
must be supplied somewhere - either way the compiler must be able to resolve T
to a type (rather than a variable or method).
Conversely the Type
class encodes type information at runtime such as its name or the assembly that a type is declared in. Activator.CreateInstance
also comes with an overload that allows you to supply an instance of Type
:
object CreateObject(Type type)
{
return Activator.CreateInstance(type);
}
In your case it looks like you don't know what the types will be at compile time, so you will be mostly working with the Type
class - you can use typeof(MyClass)
to get an instance of the the corresponding Type
for a class known at runtime, and myObject.GetType()
to get type information for an object at runtime.
Upvotes: 3
Reputation: 39916
var types = new Dictionary<Type, Type>
{
{typeof(IFoo), typeof(FooThing)},
{typeof(IBar), typeof(BarThing)},
...
}
foreach(var entry in types)
{
if(entry.Key.IsAssignableFrom(node.GetType()))
return Activator.CreateInstance(entry.Value);
}
return null;
Upvotes: 2