Problem with array initialization using Activator.CreateInstance

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Terry

    Problem with array initialization using Activator.CreateInstance

    I'm building some dll assemblies that have in them the implementation of an
    abstract class defined in a different assembly.

    I'm trying to create objects of the type defined in the dlls with
    "Activator.Crea teInstance".

    Everything was working fine until I started to fill out the class def with
    some implementation. At some point the CreateInstance was failing with a
    "MissingMethodE xception - No parameterless constructor defined for this
    object".

    I tracked down the problem to an array I was creating in the implementation
    of one of the methods.

    Specifically, if I create my array like this:

    byte [] myByteArray = {0xFF, 0xFF, 0xFF};

    it will throw an exception. But, if I create it like this:

    byte [] myByteArray = new byte[3];
    myByteArray[0] = 0xFF;
    etc.

    It works fine.

    I'm a bit puzzled by this. How can all function local code affect the
    creation of an object? And why would it make a difference how the array is
    created and initialized within a method of the derived class?

    Can anyone help clear this up? Am I doing something I shouldn't be?

    Thanks!


  • Jon Skeet

    #2
    Re: Problem with array initialization using Activator.Creat eInstance

    Terry <cheerio12345@h otmail.com> wrote:[color=blue]
    > I'm a bit puzzled by this. How can all function local code affect the
    > creation of an object? And why would it make a difference how the array is
    > created and initialized within a method of the derived class?
    >
    > Can anyone help clear this up? Am I doing something I shouldn't be?[/color]

    <snip>

    That sounds very odd to me. Could you provide a short but complete
    example which demonstrates the problem?
    See http://www.pobox.com/~skeet/csharp/complete.html for what I mean by
    that.

    --
    Jon Skeet - <skeet@pobox.co m>
    Pobox has been discontinued as a separate service, and all existing customers moved to the Fastmail platform.

    If replying to the group, please do not mail me too

    Comment

    • Terry

      #3
      Re: Problem with array initialization using Activator.Creat eInstance

      Ok. Here it is. Here's a simple test case which demonstrates the problem
      I'm having. If I'm doing something wrong, please let me know.

      There are 3 projects created. One is the "interface dll" which contains the
      abstract class. Another is the "implementa tion dll" which contains a class
      that derives from and implements the abstract class. And there's a Windows
      forms app to use as the driver. Here are the steps and code.

      1. Create a "Class library" project. This will define an abstract class to
      act as an interface. Call it "InterfaceD ll".

      Here is the code for the source file in this project. Compile it.

      using System;
      namespace InterfaceDll
      {
      /// <summary>
      /// Summary description for Class1.
      /// </summary>
      public abstract class TheInterface
      {
      public abstract int DoSomething1();
      public abstract int DoSomething2();
      }
      }

      2. Create another "Class library" project. Call it "Implementation Dll".
      Add a project reference to the built "InterfaceD ll" you created in step one.
      Here is the source for this one.

      using System;
      namespace ImplementationD ll
      {
      /// <summary>
      /// Summary description for Class1.
      /// </summary>
      public class Implementation : InterfaceDll.Th eInterface
      {
      public Implementation( )
      {
      }
      public override int DoSomething1()
      {
      //byte[] myBytes = {0xFF, 0xFF, 0xFF, 0xFF};
      //foreach (byte b in myBytes)
      //{
      // Console.Write(b .ToString() );
      //}
      return 0;
      }
      public override int DoSomething2()
      {
      return 0;
      }
      }
      }

      * Note the lines commented out. Leave them commented out for now. Build
      this dll.

      3. Create a Windows forms app with a single button on the form. Add a
      reference to the "InterfaceDll.d ll" built in step 1 to this project. Add a
      click handler for the button. Add the following code to the button handler.

      string strCurDir = Environment.Cur rentDirectory;
      string filename = Path.Combine(st rCurDir, "implementation dll.dll" );
      //Load the Assembly
      Assembly a = Assembly.LoadFr om(filename);
      // get all the types in the loaded assembly
      Type[] types = a.GetTypes();
      foreach (Type typ in types)
      {
      // dynamically create or activate(if exist) object
      object obj = Activator.Creat eInstance(typ);
      }

      Build the forms app. Now, copy the "Implementation Dll.dll" from step 2 into
      the "\bin\Debug " directory so the code can locate the assembly.

      4. Run the windows forms app. Click the button. Note how it runs
      properly.

      5. Now, uncomment the code in the "DoSomethin g1" method in the
      "Implementation Dll" project, build it and (DON'T FORGET) copy the new dll
      into the same location as in step 3.

      6. Run the windows forms app again. Click the button. It will throw an
      exception on the "object obj = Activator.Creat eInstance(typ); " line.

      "An unhandled exception of type 'System.Missing MethodException '
      occurred in mscorlib.dll
      Additional information: No parameterless constructor defined for
      this object."

      If you change the byte[] array allocation to use "new" instead of an
      initializer list like the following, it works ok.

      byte[] myBytes = new byte[4];
      myBytes[0] = myBytes[1] = myBytes[2] = myBytes[3] = 0xFF;

      Why does using an initializer for the byte[] array in the "DoSomethin g1"
      method cause an error? Am I doing something wrong?

      Thanks!

      Terry



      "Jon Skeet" <skeet@pobox.co m> wrote in message
      news:MPG.19cf88 f728a7576a9896a c@news.microsof t.com...[color=blue]
      > Terry <cheerio12345@h otmail.com> wrote:[color=green]
      > > I'm a bit puzzled by this. How can all function local code affect the
      > > creation of an object? And why would it make a difference how the array[/color][/color]
      is[color=blue][color=green]
      > > created and initialized within a method of the derived class?
      > >
      > > Can anyone help clear this up? Am I doing something I shouldn't be?[/color]
      >
      > <snip>
      >
      > That sounds very odd to me. Could you provide a short but complete
      > example which demonstrates the problem?
      > See http://www.pobox.com/~skeet/csharp/complete.html for what I mean by
      > that.
      >
      > --
      > Jon Skeet - <skeet@pobox.co m>
      > http://www.pobox.com/~skeet
      > If replying to the group, please do not mail me too[/color]


      Comment

      • Jon Skeet

        #4
        Re: Problem with array initialization using Activator.Creat eInstance

        Terry <cheerio12345@h otmail.com> wrote:[color=blue]
        > Ok. Here it is. Here's a simple test case which demonstrates the problem
        > I'm having. If I'm doing something wrong, please let me know.[/color]

        <snip>

        Brief request - I reckon it's generally easier to do this kind of thing
        with console apps. In fact, you don't even need the three different
        classes here. Here's a short class which demonstrates everything:

        using System;
        using System.Reflecti on;

        class Test
        {
        public static void Main()
        {
        try
        {
        foreach (Type t in
        Assembly.GetExe cutingAssembly( ).GetTypes())
        {
        Console.WriteLi ne (t.Name);
        Activator.Creat eInstance (t);
        }
        }
        catch (Exception e)
        {
        Console.WriteLi ne (e);
        }
        }

        public void Foo()
        {
        byte[] myBytes = {0xFF, 0xFF, 0xFF, 0xFF};
        }
        }


        Even with the three-class system a console app would end up being
        shorter to demonstrate with. Anyway, on with the problem itself.


        You're iterating over *all* the types within the assembly - and the one
        which is failing (at least on my system) is a type called:
        <PrivateImpleme ntationDetails> (including the angle brackets).

        If you compile the console app above and run it, you'll see the same
        thing. Comment out the line in Foo and it runs fine. Comment out the
        line using Activator.Creat eInstance instead, and you'll get something
        like:

        Test
        <PrivateImpleme ntationDetails>
        $$struct0x60000 02-1

        Now, using Reflector (http://www.aisto.com/roeder/dotnet/) or ildasm
        you can have a look and see that the struct is nested within
        <PrivateImpleme ntationDetails> . I believe it basically contains the
        initialisation data for the byte array. Add some more arrays and you'll
        see the same thing, growing and growing. Look at mscorlib and there are
        loads of them.

        The upshot of this is that you should basically take more care about
        which types you want to create instances of, although I agree it's a
        somewhat surprising case. If you only look at public types (using
        Type.IsPublic) you should be fine.

        --
        Jon Skeet - <skeet@pobox.co m>
        Pobox has been discontinued as a separate service, and all existing customers moved to the Fastmail platform.

        If replying to the group, please do not mail me too

        Comment

        • Terry

          #5
          Re: Problem with array initialization using Activator.Creat eInstance

          Ah. I see. Thank you very much! You're a credit to the Internet! :-)

          Terry

          "Jon Skeet" <skeet@pobox.co m> wrote in message
          news:MPG.19d0c6 d35c152a409896b 6@news.microsof t.com...[color=blue]
          > Terry <cheerio12345@h otmail.com> wrote:[color=green]
          > > Ok. Here it is. Here's a simple test case which demonstrates the[/color][/color]
          problem[color=blue][color=green]
          > > I'm having. If I'm doing something wrong, please let me know.[/color]
          >
          > <snip>
          >
          > Brief request - I reckon it's generally easier to do this kind of thing
          > with console apps. In fact, you don't even need the three different
          > classes here. Here's a short class which demonstrates everything:
          >
          > using System;
          > using System.Reflecti on;
          >
          > class Test
          > {
          > public static void Main()
          > {
          > try
          > {
          > foreach (Type t in
          > Assembly.GetExe cutingAssembly( ).GetTypes())
          > {
          > Console.WriteLi ne (t.Name);
          > Activator.Creat eInstance (t);
          > }
          > }
          > catch (Exception e)
          > {
          > Console.WriteLi ne (e);
          > }
          > }
          >
          > public void Foo()
          > {
          > byte[] myBytes = {0xFF, 0xFF, 0xFF, 0xFF};
          > }
          > }
          >
          >
          > Even with the three-class system a console app would end up being
          > shorter to demonstrate with. Anyway, on with the problem itself.
          >
          >
          > You're iterating over *all* the types within the assembly - and the one
          > which is failing (at least on my system) is a type called:
          > <PrivateImpleme ntationDetails> (including the angle brackets).
          >
          > If you compile the console app above and run it, you'll see the same
          > thing. Comment out the line in Foo and it runs fine. Comment out the
          > line using Activator.Creat eInstance instead, and you'll get something
          > like:
          >
          > Test
          > <PrivateImpleme ntationDetails>
          > $$struct0x60000 02-1
          >
          > Now, using Reflector (http://www.aisto.com/roeder/dotnet/) or ildasm
          > you can have a look and see that the struct is nested within
          > <PrivateImpleme ntationDetails> . I believe it basically contains the
          > initialisation data for the byte array. Add some more arrays and you'll
          > see the same thing, growing and growing. Look at mscorlib and there are
          > loads of them.
          >
          > The upshot of this is that you should basically take more care about
          > which types you want to create instances of, although I agree it's a
          > somewhat surprising case. If you only look at public types (using
          > Type.IsPublic) you should be fine.
          >
          > --
          > Jon Skeet - <skeet@pobox.co m>
          > http://www.pobox.com/~skeet
          > If replying to the group, please do not mail me too[/color]


          Comment

          Working...