How do i use Activator.CreateInstance with strings?

前端 未结 5 1961
礼貌的吻别
礼貌的吻别 2021-02-05 01:48

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


        
相关标签:
5条回答
  • 2021-02-05 02:11

    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);
    }
    
    0 讨论(0)
  • 2021-02-05 02:14

    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 ());
    
    0 讨论(0)
  • 2021-02-05 02:15

    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);
    
    0 讨论(0)
  • 2021-02-05 02:27

    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?

    0 讨论(0)
  • 2021-02-05 02:31

    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...

    0 讨论(0)
提交回复
热议问题