Подтвердить что ты не робот

Как использовать Activator.CreateInstance со строками?

В моем коде отражения я попал в проблему с моим общим разделом кода. В частности, когда я использую строку.

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.

Как создать строку с использованием отражения?

4b9b3361

Ответ 1

Имейте в виду, что класс string неизменен. Он не может быть изменен после его создания. Это объясняет, почему у него нет конструктора без параметров, он никогда не сможет создать полезный строковый объект, отличный от пустой строки. Это уже доступно на языке С#, это "".

То же рассуждение применяется для конструктора строки (String). Нет смысла дублировать строку, строка, которую вы передадите конструктору, уже является прекрасным экземпляром строки.

Итак, исправьте свою проблему, проверив для случая строки:

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

Ответ 2

Вы пытаетесь сделать это:

var sz = new string();

Попробуйте скомпилировать его, вы поймете свою ошибку.

Вы можете попробовать:

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

Но это выглядит бесполезным, вы должны прямо использовать значение...

Ответ 3

Похоже, вы пытаетесь вызвать конструктор, который просто берет строку - и нет такого конструктора. Если у вас уже есть строка, почему вы пытаетесь создать новую? (Если вы не указали никаких дополнительных аргументов, вы пытались вызвать конструктор без параметров, который опять же не существует.)

Обратите внимание, что typeof(string) - это более простой способ получить ссылку на тип строки.

Не могли бы вы дать нам больше информации о более общей картине того, что вы пытаетесь сделать?

Ответ 4

Строка фактически не имеет конструктора, который принимает строку как входную. Существует конструктор, который принимает массив char, поэтому это должно работать:

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

Ответ 5

Это то, что я использую в своих проектах. Насколько мне нужно создать экземпляр типа объекта и не знать во время разработки, для меня это довольно нормально. Возможно, вы путешествуете по объектным свойствам и хотите их динамически создавать. Мне нужно много раз создавать, а затем присваивать значения объектам без инстанцирования 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);
}