如何在运行时生成未知类型的实例?

时间:2009-11-12 14:17:59

标签: c# .net types runtime

我在C#中有以下内容:

string typename = "System.Int32";
string value = "4";

这两个字符串应该用于生成具有指定值的指定类型的对象...

结果应为:

object o = CreateUnknownType(typename, value);
...
Int32 test = (Int32)o;

8 个答案:

答案 0 :(得分:20)

这是你在想什么?

object result = Convert.ChangeType("4", Type.GetType("System.Int32"));

答案 1 :(得分:15)

如上所述,这太宽泛,一般无法解决。

以下是一些选项:

Type type = Type.GetType(typename);
object o = Activator.CreateInstance(type);

这将创建typename描述的类型的实例。它调用该类型的无参数构造函数。 (下行:并非所有对象都有无参数构造函数。此外,这会使用value设置对象的状态。)

Type type = Type.GetType(typename);
object o = Activator.CreateInstance(type, new[] { value });

这将创建typename描述的类型的实例。它调用该类型的构造函数,该构造函数接受一个类型为string的参数。 (下行:并非所有对象都有这样的构造函数。例如,Int32没有这样的构造函数,因此您将遇到运行时异常。)

Type type = Type.GetType(typename);
object o = Convert.ChangeType(value, type);

这将尝试将字符串value转换为所需类型的实例。这可能导致InvalidCastException s。例如,Convert.ChangeType("4", typeof(FileStream))显然会失败,因为它应该。

实际上,最后一个示例(创建类型FileStream的实例,其初始状态由字符串"4"确定)显示了一般问题的荒谬程度。有一些建设/转换是无法完成的。

你可能想重新考虑你想要解决的问题,以避免这种困境。

答案 2 :(得分:3)

创建一个你知道的类型的实例(并且应该有一个默认的构造函数):

   string typeName = "System.Int32";
   Type type = Type.GetType(type);
   object o = Activator.CreateInstance(type);

从字符串中解析一个值显然只适用于一组有限的类型。你可以

  • 按照建议使用Convert.ChangeType 作者:PhilipW
  • 或者可能创建一个 Dictionary<Type,Func<string,object>> 将已知类型映射到已知解析 功能
  • 或使用反射来调用 关于类型的Parse(字符串)方法, 假设有一个:

       string valueText = "4";
       MethodInfo parseMethod = type.GetMethod("Parse");
       object value = parseMethod.Invoke(null, new object[] { valueText });
    
  • 或者你可以使用 .NET提供的基础架构 组件模型。你可以拿到 组件的类型转换器和使用 它是这样的:

       TypeConverter converter = TypeDescriptor.GetConverter(type);
       object value = converter.ConvertFromString(valueText);
    

答案 3 :(得分:1)

你的逻辑似乎有点瑕疵。显然,如果你以后直接将对象转换为它的实际类型,那么你必须知道要开始的类型。

如果这个问题中还缺少其他内容,请详细说明,或许还有一个更合适的答案,而不仅仅是“这没有多大意义。”

答案 4 :(得分:1)

也许您有一组不同的类型,所有类型都实现了一个已知的接口?

例如,如果你有几个不同的用户控件并希望将其中一个加载到一个容器中,那么每一个都可以实现IMyWobblyControl(一个已知的接口),但是你可能直到运行时才知道要加载它们,可能是从读取字符串从某种形式的配置文件。

在这种情况下,您需要使用反射从类似于完整程序集名称的内容加载实际类型,然后将其转换为已知类型以使用它。

当然,您需要确保您的代码处理无效的强制转换,未找到的程序集以及可能通过某些内容发生的任何其他异常......

答案 5 :(得分:0)

这似乎是Int32.Parse(字符串)的工作。但是为了与其他人一致,它似乎是“独一无二的”,人们可能应该想到手套。

答案 6 :(得分:0)

使用后:

Type type = Type.GetType(typename);

试试这个扩展方法:

public static class ReflectionExtensions
{
    public static T CreateInstance<T>(this Type source, params object[] objects)
        where T : class
    {            
        var cons = source.GetConstructor(objects.Select(x => x.GetType()).ToArray());
        return cons == null ? null : (T)cons.Invoke(objects);
    }
}

希望这有帮助。

答案 7 :(得分:0)

以下是涉及Azure SQL Federations的问题的一个具体示例...它根据键范围将数据拆分为单独的数据库。

关键范围类型是:

SQL / .Net SQL类型 / CLR .Net

INT / SqlInt32 / Int32,Nullable

BIGINT / SqlInt64 / Int64,Nullable

UNIQUEIDENTIFIER / SqlGuid / Guid,Nullable

VARBINARY(n),max n 900 / SqlBytes,SqlBinary / Byte []

理想情况下,C#函数param可以采用.Net SQL类型或CLR .Net类型,但只关注一类类型就可以了。

“对象”类型参数是否可行?并且,是否有可行的方法来识别类型并相应地转换它?

概念如下:

public void fn(object obj,string fedName,string distName,bool filteringOn)

{

...找出obj的类型,以确保它是可接受的类型之一...

string key = obj.toString();

返回string.Format(“USE FEDERATION {0}({1} ='{2}')WITH RESET,FILTERING = {3}”,fedName,distName,key,(filteringOn?“ON”:“OFF” “));

}

虽然param值被强制转换为字符串,但它将在sql server端进行重新/检查,因此需要在app端进行验证。