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

发布于 2024-08-11 18:11:17 字数 253 浏览 4 评论 0原文

我在 C# 中有以下内容:

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

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

结果应该是:

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

i've got the following in C#:

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

theses two strings should be taken to generate an object of the specified type with the specified value...

result should be:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

没有伤那来痛 2024-08-18 18:11:17

这就是你的想法吗?

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

Is this what are you are thinking?

object result = Convert.ChangeType("4", Type.GetType("System.Int32"));
放低过去 2024-08-18 18:11:17

如前所述,这个问题太宽泛,无法普遍解决。

以下是一些选项:

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 。例如,Convert.ChangeType("4", typeof(FileStream)) 显然会失败,正如它应该的那样。

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

您可能需要重新思考您正在尝试解决的问题,以避免陷入困境。

As stated, this is too broad and can not be solved generally.

Here are some options:

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

This will create an instance of the type that typename is describing. It calls the parameterless constructor of that type. (Downside: Not all objects have a parameterless constructor. Further, this does set the state of the object using value.)

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

This will create an instance of the type that typename is describing. It calls a constructor of that type that accepts one parameter of type string. (Downside: Not all objects have such a constructor. For example, Int32 does not have such a constructor so you will experience a runtime exception.)

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

This will attempt to convert the string value to an instance of the required type. This can lead to InvalidCastExceptions though. For example, Convert.ChangeType("4", typeof(FileStream)) will obviously fail, as it should.

In fact, this last example (create an instance of type FileStream with its initial state determined by the string "4") shows how absurd the general problem is. There are some constructions/conversions that just can not be done.

You might want to rethink the problem you are trying to solve to avoid this morass.

喜爱皱眉﹌ 2024-08-18 18:11:17

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

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

从字符串中解析值显然只适用于有限的类型集。您可以

  • 按照建议使用 Convert.ChangeType
    由 PhilipW
  • 或者创建一个
    字典<类型,函数<字符串,对象>>
    它将已知类型映射到已知解析
    函数
  • 或使用反射来调用
    类型上的 Parse(string) 方法,
    假设有一个:

     string valueText = "4";
       MethodInfo parseMethod = type.GetMethod("解析");
       对象值 = parseMethod.Invoke(null, new object[] { valueText });
    
  • 或者也许你可以使用
    .NET 提供的基础设施
    组件模型。您可以获取
    组件的类型转换器和使用
    像这样:

     TypeConverter转换器 = TypeDescriptor.GetConverter(type);
       对象值=转换器.ConvertFromString(valueText);
    

Creating an instance of a type you know by name (and which should have a default constructor):

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

Parsing a value from a string will obviously only work for a limited set of types. You could

  • use Convert.ChangeType as suggested
    by PhilipW
  • or maybe create a
    Dictionary<Type,Func<string,object>>
    which maps known types to known parse
    functions
  • or use reflection to invoke the
    Parse(string) method on the type,
    assuming there is one:

       string valueText = "4";
       MethodInfo parseMethod = type.GetMethod("Parse");
       object value = parseMethod.Invoke(null, new object[] { valueText });
    
  • or maybe you can use the
    infrastructure provided by the .NET
    component model. You can fetch the
    type converter of a component and use
    it like this:

       TypeConverter converter = TypeDescriptor.GetConverter(type);
       object value = converter.ConvertFromString(valueText);
    
没有你我更好 2024-08-18 18:11:17

你的逻辑在这里似乎有点缺陷。显然,如果您稍后直接将对象转换为它的实际类型,那么您必须首先知道该类型。

如果这个问题还缺少其他内容,请详细说明,也许有一个比简单地“这没有多大意义”更合适的答案。

Your logic seems a little flawed here. Obviously, if you're directly casting the object at a later time to the actual type it is, then you must know the type to begin with.

If there's something else that is missing from this question please elaborate and maybe there is a more appropriate answer than simply, "This doesn't make much sense."

梦纸 2024-08-18 18:11:17

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

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

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

当然,您需要确保您的代码能够处理无效的转换、未找到程序集以及可能因像这样不稳定的情况而出现的任何其他异常...

Perhaps you have a set of different types, all of which implement a known interface?

For example if you have several different user controls and want to load one of them into a container, each one might implement IMyWobblyControl (a known interface) yet you might not know until runtime which of them to load, possibly from reading strings from some form of configuration file.

In that case, you'll need to use reflection to load the actual type from something like the full assembly name, then cast it into your known type to use it.

Of course, you need to make sure that your code handles invalid cast, assembly not found and any of the other exceptions that are likely to come along through something as wobbly as this...

清风挽心 2024-08-18 18:11:17

这似乎是 Int32.Parse(string) 的工作。但同意其他人的观点,这似乎是“独特的”,人们可能应该想到手套。

This seems like a job for Int32.Parse(string). But to agree with the others it seems this is "unique" and one should probably think gloves.

反目相谮 2024-08-18 18:11:17

这是涉及 Azure SQL 联合的问题的具体示例...它根据键范围将数据拆分为单独的数据库。

键范围类型为:

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# 函数参数可以采用 .Net SQL 类型或 CLR .Net 类型,但只选择一类类型很好。

“对象”类型参数是可行的方法吗?那么,是否有一种可行的方法来识别类型并进行相应的转换?

这个概念类似于:

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

{

...弄清楚 obj 是什么类型以确保它是可接受的类型之一...

string key = obj.toString ();

return string.Format("使用 FEDERATION {0} ({1}='{2}') 重置,FILTERING = {3}", fedName, distName, key, (filteringOn ? "ON" : "OFF")) ;

虽然

参数值被转换为字符串,但它将在 sql 服务器端重新转换/检查,因此需要在应用程序端验证它。

Here's a specific example of the problem involving Azure SQL Federations...which splits data into separate db's according to a key range.

The key range types are:

SQL / .Net SQL type / CLR .Net

INT / SqlInt32 / Int32, Nullable

BIGINT / SqlInt64 / Int64, Nullable

UNIQUEIDENTIFIER / SqlGuid /Guid, Nullable

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

Ideally, a C# function param could take either .Net SQL type or CLR .Net type but settling on just one category of type is fine.

Would an "object" type param be the way to go? And, is there a feasible way to identify the type and convert it accordingly?

The concept is something like:

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

{

...figure out what type obj is to ensure it is one of the acceptable types...

string key = obj.toString();

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

}

Though the param value is cast to string, it will be recast/checked on the sql server side so validating it on the app side is desired.

情绪少女 2024-08-18 18:11:17

使用后:

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

希望这有帮助。

After using:

Type type = Type.GetType(typename);

Try this extension method:

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

Hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文