如何将 Activator.CreateInstance 与字符串一起使用?

发布于 2024-08-18 12:21:14 字数 714 浏览 8 评论 0原文

在我的反射代码中,我的通用代码部分遇到了问题。特别是当我使用字符串时。

var oVal = (object)"Test";
var oType = oVal.GetType();
var sz = Activator.CreateInstance(oType, oVal);

例外

An unhandled exception of type 'System.MissingMethodException' occurred in mscorlib.dll

Additional information: Constructor on type 'System.String' not found.

这个单行中,

var sz = Activator.CreateInstance("".GetType(), "Test");

我出于测试目的尝试了这个,它也出现在我最初写的

var sz = Activator.CreateInstance("".GetType());

但我收到此错误

Additional information: No parameterless constructor defined for this object.

如何使用反射创建字符串?

In my reflection code i hit a problem with my generic section of code. Specifically when i use a string.

var oVal = (object)"Test";
var oType = oVal.GetType();
var sz = Activator.CreateInstance(oType, oVal);

Exception

An unhandled exception of type 'System.MissingMethodException' occurred in mscorlib.dll

Additional information: Constructor on type 'System.String' not found.

I tried this for testing purposes and it occurs in this single liner too

var sz = Activator.CreateInstance("".GetType(), "Test");

originally i wrote

var sz = Activator.CreateInstance("".GetType());

but i get this error

Additional information: No parameterless constructor defined for this object.

How do i create a string using reflection?

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

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

发布评论

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

评论(5

憧憬巴黎街头的黎明 2024-08-25 12:21:14

请记住,字符串类是不可变的。创建后就无法更改。这解释了为什么它没有无参数构造函数,它永远无法生成除空字符串之外的有用字符串对象。这在 C# 语言中已经可用,它就是“”。

同样的推理也适用于字符串(String)构造函数。复制字符串是没有意义的,您传递给构造函数的字符串已经是该字符串的一个完美的实例。

因此,通过测试字符串大小写来解决您的问题:

var oType = oVal.GetType();
if (oType == typeof(string)) return oVal as string;
else return Activator.CreateInstance(oType, oVal);

Keep in mind that the string class is immutable. It cannot be changed after it is created. That explains why it doesn't have a parameterless constructor, it could never generate a useful string object other than an empty string. That's already available in the C# language, it is "".

Same reasoning applies for a string(String) constructor. There is no point in duplicating a string, the string you'd pass to the constructor is already a perfectly good instance of the string.

So fix your problem by testing for the string case:

var oType = oVal.GetType();
if (oType == typeof(string)) return oVal as string;
else return Activator.CreateInstance(oType, oVal);
ゃ懵逼小萝莉 2024-08-25 12:21:14

你正在尝试这样做:

var sz = new string();

尝试编译它,你就会明白你的错误。

你可以尝试:

var sz = Activator.CreateInstance(typeof(string), new object[] {"value".ToCharArray()});

但它看起来没什么用,你应该直接使用值......

You are trying to do this :

var sz = new string();

Try to compile it, you will understand your error.

You may try :

var sz = Activator.CreateInstance(typeof(string), new object[] {"value".ToCharArray()});

But it looks useless, you should directly use value...

半葬歌 2024-08-25 12:21:14

看起来您正在尝试调用一个仅接受字符串的构造函数 - 但没有这样的构造函数。如果您已经得到了一个字符串,为什么还要尝试创建一个新字符串呢? (当您没有提供任何进一步的参数时,您试图调用无参数构造函数 - 同样,它不存在。)

请注意,typeof(string) 是获取引用的更简单方法到字符串类型。

您能否向我们提供更多有关您正在尝试做的事情的总体情况的信息?

It looks like you're trying to call a constructor which just takes a string - and there isn't such a constructor. If you've already got a string, why are you trying to create a new one? (When you didn't provide any further arguments, you were trying to call a parameterless constructor - which again, doesn't exist.)

Note that typeof(string) is a simpler way to get a reference to the string type.

Could you give us more information about the bigger picture of what you're trying to do?

唔猫 2024-08-25 12:21:14

String 实际上没有将字符串作为输入的构造函数。有一个接受 char 数组的构造函数,因此这应该可以工作:

var sz = Activator.CreateInstance ("".GetType (), "Test".ToCharArray ());

String actually has no constructor that takes a string as input. There is a constructor that takes a char array so this should work:

var sz = Activator.CreateInstance ("".GetType (), "Test".ToCharArray ());
奢欲 2024-08-25 12:21:14

这就是我在我的项目中使用的。至于需要创建某种类型的对象的实例化并且在设计时不知道,这对我来说是相当正常的。也许您正在循环访问对象属性,并且希望动态实例化所有对象属性。我有很多次需要创建然后将值分配给非实例化的 POCO 对象...使用下面的代码,您可以使用存储在数据库中的字符串值来实例化对象,或者实例化存储在引用您的库中的对象库 - 这样您也可以绕过循环引用错误...希望它有帮助。

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;

/// <summary>
/// Instantiates an object. Must pass PropertyType.AssemblyQualifiedName for factory to operate
/// returns instantiated object
/// </summary>
/// <param name="typeName"></param>
/// <returns></returns>
public static object Create(string typeAssemblyQualifiedName)
{
  // resolve the type
  Type targetType = ResolveType(typeAssemblyQualifiedName);
  if (targetType == null)
    throw new ArgumentException("Unable to resolve object type: " + typeAssemblyQualifiedName);

  return Create(targetType);
}

/// <summary>
/// create by type of T
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T Create<T>()
{
  Type targetType = typeof(T);
  return (T)Create(targetType);
}

/// <summary>
/// general object creation
/// </summary>
/// <param name="targetType"></param>
/// <returns></returns>
public static object Create(Type targetType)
{
  //string test first - it has no parameterless constructor
  if (Type.GetTypeCode(targetType) == TypeCode.String)
    return string.Empty;

  // get the default constructor and instantiate
  Type[] types = new Type[0];
  ConstructorInfo info = targetType.GetConstructor(types);
  object targetObject = null;

  if (info == null) //must not have found the constructor
    if (targetType.BaseType.UnderlyingSystemType.FullName.Contains("Enum"))
      targetObject = Activator.CreateInstance(targetType);
    else
      throw new ArgumentException("Unable to instantiate type: " + targetType.AssemblyQualifiedName + " - Constructor not found");
  else
    targetObject = info.Invoke(null);

  if (targetObject == null)
    throw new ArgumentException("Unable to instantiate type: " + targetType.AssemblyQualifiedName + " - Unknown Error");
  return targetObject;
}

/// <summary>
/// Loads the assembly of an object. Must pass PropertyType.AssemblyQualifiedName for factory to operate
/// Returns the object type.
/// </summary>
/// <param name="typeString"></param>
/// <returns></returns>
public static Type ResolveType(string typeAssemblyQualifiedName)
{
  int commaIndex = typeAssemblyQualifiedName.IndexOf(",");
  string className = typeAssemblyQualifiedName.Substring(0, commaIndex).Trim();
  string assemblyName = typeAssemblyQualifiedName.Substring(commaIndex + 1).Trim();

  if (className.Contains("[]"))
    className.Remove(className.IndexOf("[]"), 2);

  // Get the assembly containing the handler
  Assembly assembly = null;
  try
  {
    assembly = Assembly.Load(assemblyName);
  }
  catch
  {
    try
    {
      assembly = Assembly.LoadWithPartialName(assemblyName);//yes yes this is obsolete but it is only a backup call
    }
    catch
    {
      throw new ArgumentException("Can't load assembly " + assemblyName);
    }
  }

  // Get the handler
  return assembly.GetType(className, false, false);
}

This is what I use in my projects. As far as needing to create an instantiation of a type of object and not knowing at design time, is rather normal for me. Perhaps you are cycling through object properties and you want to instantiate all of them dynamically. I have many times needed to create then assign values to non instantiated POCO objects... with the below code you can use a string value stored in the DB to instantiate an object as well or instantiate an object stored in a library that is referencing your library - so you can bypass circular reference errors as well... Hope it helps.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;

/// <summary>
/// Instantiates an object. Must pass PropertyType.AssemblyQualifiedName for factory to operate
/// returns instantiated object
/// </summary>
/// <param name="typeName"></param>
/// <returns></returns>
public static object Create(string typeAssemblyQualifiedName)
{
  // resolve the type
  Type targetType = ResolveType(typeAssemblyQualifiedName);
  if (targetType == null)
    throw new ArgumentException("Unable to resolve object type: " + typeAssemblyQualifiedName);

  return Create(targetType);
}

/// <summary>
/// create by type of T
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T Create<T>()
{
  Type targetType = typeof(T);
  return (T)Create(targetType);
}

/// <summary>
/// general object creation
/// </summary>
/// <param name="targetType"></param>
/// <returns></returns>
public static object Create(Type targetType)
{
  //string test first - it has no parameterless constructor
  if (Type.GetTypeCode(targetType) == TypeCode.String)
    return string.Empty;

  // get the default constructor and instantiate
  Type[] types = new Type[0];
  ConstructorInfo info = targetType.GetConstructor(types);
  object targetObject = null;

  if (info == null) //must not have found the constructor
    if (targetType.BaseType.UnderlyingSystemType.FullName.Contains("Enum"))
      targetObject = Activator.CreateInstance(targetType);
    else
      throw new ArgumentException("Unable to instantiate type: " + targetType.AssemblyQualifiedName + " - Constructor not found");
  else
    targetObject = info.Invoke(null);

  if (targetObject == null)
    throw new ArgumentException("Unable to instantiate type: " + targetType.AssemblyQualifiedName + " - Unknown Error");
  return targetObject;
}

/// <summary>
/// Loads the assembly of an object. Must pass PropertyType.AssemblyQualifiedName for factory to operate
/// Returns the object type.
/// </summary>
/// <param name="typeString"></param>
/// <returns></returns>
public static Type ResolveType(string typeAssemblyQualifiedName)
{
  int commaIndex = typeAssemblyQualifiedName.IndexOf(",");
  string className = typeAssemblyQualifiedName.Substring(0, commaIndex).Trim();
  string assemblyName = typeAssemblyQualifiedName.Substring(commaIndex + 1).Trim();

  if (className.Contains("[]"))
    className.Remove(className.IndexOf("[]"), 2);

  // Get the assembly containing the handler
  Assembly assembly = null;
  try
  {
    assembly = Assembly.Load(assemblyName);
  }
  catch
  {
    try
    {
      assembly = Assembly.LoadWithPartialName(assemblyName);//yes yes this is obsolete but it is only a backup call
    }
    catch
    {
      throw new ArgumentException("Can't load assembly " + assemblyName);
    }
  }

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