简体   繁体   中英

Returning desired type from Activator.CreateInstance() instead of object

I'm trying to create an instance of specified Type whatever user wants to have. For a quick illustration of my purpose please see the code below:

    static void Main(string[] args)
    {
        object o = GetInstance(typeof(int));
        Console.WriteLine("Created type: {0}", o.GetType().FullName);
    }

    public static object GetInstance(Type t)
    {
        Console.WriteLine("Creating instance of {0}", t.FullName);
        return Activator.CreateInstance(t);
    }

The problem is Activator.CreateInstance() returns object by default. There is also an overload of this method like T Activator.CreateInstance<T>() which is parameterless and returns the type you specify as T .

However, the problem is T should be hard-coded while calling this method and thus should be a fixed value. I am trying to create an instance of desired class and return it as its type.

Right now if you use this method you should write something like:

int i = GetInstance(typeof(int)) as int

I'm trying to reduce this to:

int i = GetInstance(typeof(int))

Is there a way that I can do casting inside the GetInstance and get rid of that as int repetition? By this way, my return type (and also the type I cast the object to) will be unknown at compile time .

Seemed impossible by design to me but I'd really appreciate if you figure it out.

EDIT: Where I'm stuck is eg while you're casting, you can do return (T) result if you are in a generic method, but you can't do Type t = ...; return (t) result Type t = ...; return (t) result this doesn't work. You cannot cast to a type which is passed to you as a parameter which is not known at compile time .

Follow a known pattern

This is not a new problem. It is a problem facing any API that allows type-specific return values. For example, a JSON parsing library like Newtonsoft (which is, to wit, the single most popular .NET package downloaded by .NET programmers in 2019) must be able to parse a string and return a type-specific object, which may or may not be known at compile time. It might make sense to follow their example.

Newtonsoft exposes three ways to specify the type when deserializing. You could do as you are currently doing:

//Cast required
var result = JsonConvert.DeserializeObject(text, typeof(MyType)) as MyType;  

You can use a generic method:

//No cast required, but you have to hardcode a type as a type parameter
var result = JsonConvert.DeserializeObject<MyType>(text);  

Or you can use an instance as a template, which is great for anonymous types, although you can use it with non-anonymous classes as well. This one works via generic type inference:

//No cast required and no need to specify type; the type is inferred from the argument
var result = JsonConvert.DeserializeAnonymousType(text, new MyType());  

Here's how you'd do it:

So for you to make this work, your code might look like this:

public object GetInstance(Type type)
{
    return Activator.CreateInstance(type);
}

int i = GetInstance(typeof(int)) as int;


public T GetInstance<T>()
{
    return Activator.CreateInstance<T>();
}

int i = GetInstance<int>();


public T GetInstance<T>(T template)
{
    return Activator.CreateInstance<T>();
}

int i = GetInstance(0);

If you do it this way, it's hard to imagine any programmer would have trouble using your library, as the approach should already be familiar to them.

Actually you could write GetInstance like this:

static T GetInstance<T>()
{
    return Activator.CreateInstance<T>();
}

And use it:

int j = GetInstance<int>();

This might help you to create instance of desired type:

public class ConcreteFactory<T>  : AbstractFactory<T>
    {
        public override T CreateInstance(string typeName,params object[] parameters)
        {
            var path = Assembly.GetExecutingAssembly().CodeBase;
            var assembly = Assembly.LoadFrom(path);
            var type = assembly.GetTypes().SingleOrDefault(t => t.Name == typeName);
            return (T)Activator.CreateInstance(type, parameters);
        }
}

Key here is generic type T can be used to cast the created instance, this can be used as a template to create instance of any type with parameterized constructor

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM