web-dev-qa-db-ja.com

文字列で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.

リフレクションを使用して文字列を作成するにはどうすればよいですか?

29
user34537

文字列クラスは不変であることに注意してください。作成後は変更できません。これが、パラメーターのないコンストラクターがない理由を説明しています。空の文字列以外の便利な文字列オブジェクトを生成することはできません。これはすでにC#言語で利用可能で、「」です。

同じ理由がstring(String)コンストラクターにも当てはまります。文字列を複製しても意味がありません。コンストラクタに渡す文字列は、すでに完全に適切な文字列のインスタンスです。

文字列のケースをテストして問題を修正します。

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

あなたはこれをやろうとしている:

var sz = new string();

それをコンパイルしてみてください、あなたはあなたのエラーを理解するでしょう。

あなたは試すことができます:

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

しかし、それは役に立たないように見えます。値を直接使用する必要があります...

5
Guillaume

文字列をとるコンストラクタを呼び出そうとしているようです-そのようなコンストラクタはありません。すでにgot文字列がある場合、なぜ新しい文字列を作成しようとしているのですか? (これ以上引数を指定しなかった場合、パラメーターのないコンストラクターを呼び出そうとしましたが、これも存在しません。)

typeof(string)は、文字列型への参照を取得する最も簡単な方法です。

あなたがやろうとしていることの全体像について詳しく教えてください。

2
Jon Skeet

文字列には、実際には文字列を入力として受け取るコンストラクタはありません。 char配列を取るコンストラクターがあるため、これは機能するはずです。

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

これは私のプロジェクトで使用するものです。オブジェクトのタイプのインスタンス化を作成する必要があり、設計時に分からない限り、私にとってはかなり普通です。おそらく、オブジェクトのプロパティを循環していて、それらすべてを動的にインスタンス化したいと考えています。インスタンス化されていないPOCOオブジェクトを作成して値を割り当てる必要が何度もありました...以下のコードを使用すると、DBに格納されている文字列値を使用して、オブジェクトをインスタンス化したり、ライブラリを参照しているオブジェクトをインスタンス化したりできます。ライブラリ-循環参照エラーをバイパスすることもできます...

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