locked
Create an instance from primitive types

    Question

  • hello ,is there a way to create an instance from primitive types 
    i need to perform this operation 
    Type type = Prop.PropertyType.GetGenericArguments().First();
                    Count = (int)e.editingCell.Value;
                    var baseType = typeof(List<>);
                    var genericType = baseType.MakeGenericType(type);
                    lisSousObject = (IList)Activator.CreateInstance(genericType);
                    for(int i=0;i<Count;i++)
                    {
           // this line dosn't work for string type 
                 lisSousObject.Add(Activator.CreateInstance(type));
                    }
    the prop is just a PropertyInfo variable 
    thx 
    Monday, October 3, 2016 10:17 AM

Answers

  • Really.

    Make it something like this then:

            public static object GetDefaultValue(Type t)
            {
                if (t == typeof(string))
                {
                    return default(string);
                }
                else
                {
                    if (t.IsValueType)
                    {
                        return Activator.CreateInstance(t);
                    }
                    else
                    {
                        System.Reflection.ConstructorInfo cinfo = t.GetConstructors().Where(x => x.GetParameters().Count() == 0).FirstOrDefault();
                        if ((cinfo != null))
                        {
                            return Activator.CreateInstance(t);
                        }
                        else
                        {
                            throw new InvalidOperationException("No default constructor with no parameter is found for the type.");
                        }
                    }
                }
            }

    As you can see, Activator.CreateInstrance() cannot be called on type that does not have a "default constructor that has no parameter". Ideally you should just return null for that, and since you want "special arrangement" be made for string type, a special case has been added.

    Note that with this "special arragement", the return value for string type will still be null because it's the default value for string.

    And btw, the asker just have problem on Activator throwing exception, but don't see he has problem on returning null value. Maybe it's you who should read the question again?



    • Edited by cheong00Editor Tuesday, October 4, 2016 5:49 AM
    • Marked as answer by hessoka Wednesday, October 5, 2016 2:31 PM
    Tuesday, October 4, 2016 5:38 AM
    Answerer

All replies

  • You should not.

    However, I'd advise you to do what most deserializer does - If Type.IsValuesType is true, set the value as default(T) instead.

    Monday, October 3, 2016 10:48 AM
    Answerer
  • Can u provide the changes that should be made to my code , i didn't get what do u mean by T inside the default
    Monday, October 3, 2016 11:40 AM
  • "instance from primitive types "

    String isn't a primitive type. String is no different than every other reference type in .NET and can be created the same way.

    Your code doesn't make sense to me. You are getting the type of a property and you're assuming it is a generic type with 1 parameter (a dangerous assumption). So if you had, say, a List<string> then type would be typeof(string). You then create a new instance of List<string>. Finally, for each value in some cell, you add new instance of type (string) to the list. This code should technically work but I don't understand what you're accomplishing by using it.

    What error are you getting? Please post the relevant property information as well.

    Michael Taylor
    http://www.michaeltaylorp3.net

    Monday, October 3, 2016 2:59 PM
    Moderator
  • the error i'm geting is that the type(string) dosn't have a default constructor


    • Edited by hessoka Monday, October 3, 2016 3:50 PM
    Monday, October 3, 2016 3:46 PM
  • What should be the default value for your string? If you want null then insert that into the list. If you want a specific value then use that instead. Since strings and ref types behave the same it seems like null is the better option but I suspect you're going to want to store whatever value is in your editCells stuff that you're enumerating through. In that case, for now, just insert a dummy string and then later you'll swap it out for whatever cell you're reading.
    Monday, October 3, 2016 3:56 PM
    Moderator
  • Something like this should do:

            static void Main(string[] args)
             {
                 Type intType = Type.GetType("System.Int32");
                 Console.WriteLine(GetDefaultValue(intType));
                 Console.ReadKey();
             }
    
            public static object GetDefaultValue(Type t)
            {
                if (t.IsValueType)
                {
                    return Activator.CreateInstance(t);
                }
                else
                {
                    return null;
                }
            }

    http://stackoverflow.com/questions/2686678/in-net-at-runtime-how-to-get-the-default-value-of-a-type-from-a-type-object

    Tuesday, October 4, 2016 1:47 AM
    Answerer
  • Really.

    Make it something like this then:

            public static object GetDefaultValue(Type t)
            {
                if (t == typeof(string))
                {
                    return default(string);
                }
                else
                {
                    if (t.IsValueType)
                    {
                        return Activator.CreateInstance(t);
                    }
                    else
                    {
                        System.Reflection.ConstructorInfo cinfo = t.GetConstructors().Where(x => x.GetParameters().Count() == 0).FirstOrDefault();
                        if ((cinfo != null))
                        {
                            return Activator.CreateInstance(t);
                        }
                        else
                        {
                            throw new InvalidOperationException("No default constructor with no parameter is found for the type.");
                        }
                    }
                }
            }

    As you can see, Activator.CreateInstrance() cannot be called on type that does not have a "default constructor that has no parameter". Ideally you should just return null for that, and since you want "special arrangement" be made for string type, a special case has been added.

    Note that with this "special arragement", the return value for string type will still be null because it's the default value for string.

    And btw, the asker just have problem on Activator throwing exception, but don't see he has problem on returning null value. Maybe it's you who should read the question again?



    • Edited by cheong00Editor Tuesday, October 4, 2016 5:49 AM
    • Marked as answer by hessoka Wednesday, October 5, 2016 2:31 PM
    Tuesday, October 4, 2016 5:38 AM
    Answerer
  • Try run that on int field please...

    Please try not to provide code that is more buggy than the original one.

    Tuesday, October 4, 2016 5:47 AM
    Answerer
  • thank u all for your answers , first of all the null insertion will only work for string and not for other types like int,double... , so i solved  this using the default(T) as suggested by cheong00 ,inside a generic method :

     class Default
       {
           public Default()
           {
    
           }
           public List<T> add<T>(int count)
           {
               List<T> malist = new List<T>();
               for (int i = 0; i < count; i++)
               {
                   malist.Add(default(T));
               }
               return malist;
           }
       }

    and i changed my originale code to this

    Type type = Prop.PropertyType.GetGenericArguments().First();
                    Count = (int)e.editingCell.Value;
                    Default mydef = new Default();
                    MethodInfo geniric = mydef.GetType().GetMethod("add").MakeGenericMethod(type);
                    object MehtodInvok = geniric.Invoke(mydef, new object[] { Count });
                    lisSousObject = (IList)MehtodInvok;
    feel free to comment for any additional improvement , thank u all
    Tuesday, October 4, 2016 1:45 PM
  • Humm... I don't think he mean what you propose because that would be impossible request. There is huge number of classes, especially those from 3rd party libraries, that intentionally hide the default constructor of some of their classes private so you'll have no constructor to call with in the beginning, and some variables only tell you the "interface" type so you would have no idea on what should be the corresponding constructor. The only reasonable actions for these situations would be either to place null there or throw an exception.

    Btw, as I've explained below, your choice to feed the constructor with string parameter, will make the call fail when you attempt to use it on other type that has no contructor accepting strings, or only accept strings with specific value. If you want to do special handling on specific type, please use "type testing" illustrated above to seperate cases and put appropiate value there accordingly. IMO, just putting a String.Empty there (or if you prefer, "##########") would be way better than what you've suggested.

    Giving suggestion that is worse than original is bad, but if you do it intentionally it would be worse.


    Wednesday, October 5, 2016 2:12 AM
    Answerer
  • //sigh

    Why you always try to accuse me for something I've never said? I said it right on the first sentence that "You should not." There's nothing in my replies that I imply the code I post will return "instance of a reference object".

    Do you have problem reading English?



    Wednesday, October 5, 2016 6:55 AM
    Answerer
  • hi every one my goal here is just to be able to handle some primitive types int,double,bool... (including only the string object )  , at first i tought about using 

    Activator.CreateInstance(t);

    but i can't ,cause i'm dealing with premitives , and primitives doesn't have default constructors assigned to it , the same thing goes for the string type even thout it's an object , which leaves us with adding the null value instead into my list , but again adding a null value won't work in case the type was an int or double ...(primitives) so we need to just add a default value based on type. so instead of using :

    if(t==typeof(string)){
    
    ....
    }
    else if(t==typeof(int)){
    
    ....
    }
    .
    .
    . 
    
    
    

    i used the template option since i know that all the types that i'm dealing with have necessary a default value

     public List<T> add<T>(int count)
           {
               List<T> malist = new List<T>();
               for (int i = 0; i < count; i++)
               {
                   malist.Add(default(T));
               }
               return malist;
           }


    Wednesday, October 5, 2016 1:40 PM
  • "and primitives doesn't have default constructors assigned to it"

    All the "primitives" in C# are value types except string. All value types have a default constructor. Hence the code that Cheongg00 originally posted about using IsValueType will work for your situation. It returns the default value (default(T)) for all value types (including primitives) and null for any reference type. Have you tried this code and found that it didn't work for a particular situation? If so then please post the relevant example.

    Wednesday, October 5, 2016 2:05 PM
    Moderator
  • my bad you're right the code that CheongG00 originally work just fine,i've tested the Activator only for string so i jumped to my conclusion however there is also the type String with uper case to be added into the if statement , thx cheong00 and CoolDaTx
    Wednesday, October 5, 2016 2:47 PM
  • "however there is also the type String "

    No. C# provides aliases for the primitives and strings but they all map to the same type.

    string => String
    int => Int32
    etc.

    You do not need to account for both. In C# you can use the alias and it'll work:

    //This is always true
    typeof(string) == typeof(String)
    
    //Testing for string
    if (type == typeof(string)) ...
    
    //Does the same thing...
    if (type == typeof(String)) ...

    Wednesday, October 5, 2016 3:05 PM
    Moderator
  • "C# provides aliases for the primitives and strings but they all map to the same type"

    CoolDaTx i've tested that case before posting my answer 

      public testing(Type mytype)
            {
                if (mytype == typeof(string))
                {
                    test = default(string);
                }
                test=Activator.CreateInstance(mytype);
            }
    // and this was my main
     static void Main(string[] args)
            {
                testing test = new testing(typeof(String));
                Console.WriteLine(test.test.ToString());
            }

    when i passed the String with uppercase it didn't work



    • Edited by hessoka Thursday, October 6, 2016 7:50 AM
    Thursday, October 6, 2016 7:49 AM
  • Trust me, we do this all the time. In C# you can use either the alias or the formal name and they map to the exact same thing. Some C# devs prefer to use the formal names so you see code like this:

    Int32 int1 = 10;
    int int2 = 20;
    
    var areSameType = int1.GetType() == int2.GetType();

    But most use the aliases. The code is identical. I personally use the aliases but when I'm referring to static members on the type I use the formal name.

    int int1 = Int32.Parse("123");
    Int32 int2 = Int32.Parse("123");

    But I could just as well use the alias.

    int int1 = int.Parse("123");
    Int32 int2 = int.Parse("123");

    The code you posted doesn't compile so I cannot tell you why you're getting a different answer. But your code would (irrelevant of type) always create an instance of the type because your if statement is assigning a value that would be overwritten.

    static void Main ( string[] args )
    {
        //Both are null
        var value1 = testing(typeof(string));
        var value2 = testing(typeof(String));
    }
    
    static object testing ( Type mytype )
    {
        if (mytype == typeof(string))            
            return default(string);
                
        return Activator.CreateInstance(mytype);
    }

    Thursday, October 6, 2016 1:47 PM
    Moderator