从Activator.CreateInstance()而不是object返回所需的类型

时间:2012-11-29 01:09:59

标签: c# c#-4.0 system.reflection

我正在尝试创建任何用户想要的指定Type的实例。有关我的目的的快速说明,请参阅以下代码:

    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);
    }

问题是Activator.CreateInstance()默认返回 object 。此方法也有重载,例如T Activator.CreateInstance<T>(),它是无参数的,并返回您指定为T的类型。

然而,问题是T在调用此方法时应该是硬编码的,因此应该是固定值。我正在尝试创建所需类的实例并将其作为其类型返回。

现在,如果你使用这种方法,你应该写一些类似的东西:

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

我正在尝试将其减少为:

int i = GetInstance(typeof(int))

有没有办法可以在GetInstance内进行投射并摆脱as int重复?通过这种方式,我的返回类型(以及我将对象转换为的类型)在编译时未知

对我而言,设计似乎是不可能的,但如果你弄明白的话,我真的很感激。

编辑:我被困的地方是当你正在施法时,如果你使用的是通用方法,你可以return (T) result,但你做不到Type t = ...; return (t) result这不起作用。您无法转换为作为参数传递给您的类型,该参数在编译时是未知的

3 个答案:

答案 0 :(得分:1)

遵循已知模式

这不是一个新问题。任何允许特定类型的返回值的API都面临一个问题。例如,像Newtonsoft这样的JSON解析库(即.NET程序员在2019年下载的最流行的.NET软件包)必须能够解析字符串并返回特定于类型的对象,这可能会或可能会在编译时未知。遵循他们的榜样可能很有意义。

Newtonsoft在反序列化时提供三种方式来指定类型。您可以按照目前的方式进行操作:

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

您可以使用通用方法:

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

或者,您也可以使用实例作为模板,这对于匿名类型非常有用,尽管您也可以将其与非匿名类一起使用。这个通过通用类型推断起作用:

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

这是您的操作方式:

为使您能够完成这项工作,您的代码可能如下所示:

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);

如果以此方式进行操作,很难想象任何程序员在使用您的库时都会遇到麻烦,因为这种方法对他们来说应该已经很熟悉了。

答案 1 :(得分:0)

实际上你可以这样写GetInstance

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

并使用它:

int j = GetInstance<int>();

答案 2 :(得分:0)

这可以帮助您创建所需类型的实例:

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);
        }
}

此处的键是通用类型T,可用于强制转换创建的实例,可将其用作模板以使用参数化构造函数创建任何类型的实例