Answered InvokeMethod NullReferenceException

  • Tuesday, March 09, 2010 7:50 PM
     
      Has Code
    I have a Web App that i am running into a problem.  I have a DataSet called "DateTable" and an Adapter named "DateTableAdapter".

    Both of these work fine if i invoke them individually and through some logic testing.  What i have tried to do though is construct some logic that will build a string that represents the method to be called based on some application Enums

    Dim tmpMethod As String = "Get"
    Dim tmpParameters() As Object
    tmpMethod &= core.Type.ToString
    If Not (core.Shift = Nothing) Then
      tmpMethod &= "ByShift"
      tmpParameters = New Object() {CType(core.Line, Byte), CType(core.Shift, Byte)}
    Else
      tmpParameters = New Object() {CType(core.Line, Byte)}
    End If
    tbDateInfo = core.InvokeMethod(Of DateTableDataTable)("prodsumTableAdapters.DateTableTableAdapter", tmpMethod, tmpParameters)
    

    All the above works peachy, its when i get into the InvokeMethod part of things is where it goes wrong

    Public Shared Function InvokeMethod(Of T As New)(ByVal typeName As String, ByVal methodName As String, ByVal param() As Object) As T
      Dim calledType As Type = System.Type.GetType(typeName)
      Dim result As Object
      result = calledType.InvokeMember(methodName, Reflection.BindingFlags.Public Or Reflection.BindingFlags.DeclaredOnly Or Reflection.BindingFlags.InvokeMethod Or Reflection.BindingFlags.Instance, Nothing, Nothing, param)
      Return CType(result, T)
    End Function
    I have used various deviations of the ctype to encapsulate the InvokeMember section to return the T type.  Still get the NullReferenceException at the InvokeMember line.  Not quite sure where the problem lies in all this.  The method being invoked is not a generic method and is well defined, as you see below.

    The Method(s) Exist

    <Global.System.Diagnostics.DebuggerNonUserCodeAttribute(),  _
    Global.System.ComponentModel.Design.HelpKeywordAttribute("vs.data.TableAdapter"),  _
    Global.System.ComponentModel.DataObjectMethodAttribute(Global.System.ComponentModel.DataObjectMethodType.[Select], true)>  _
    Public Overloads Overridable Function GetProduction(ByVal line As Byte) As prodsum.DateTableDataTable
      Me.Adapter.SelectCommand = Me.CommandCollection(0)
      Me.Adapter.SelectCommand.Parameters(0).Value = CType(line,Byte)
      Dim dataTable As prodsum.DateTableDataTable = New prodsum.DateTableDataTable
      Me.Adapter.Fill(dataTable)
      Return dataTable
    End Function
    
    <Global.System.Diagnostics.DebuggerNonUserCodeAttribute(),  _
    Global.System.ComponentModel.Design.HelpKeywordAttribute("vs.data.TableAdapter"),  _
    Global.System.ComponentModel.DataObjectMethodAttribute(Global.System.ComponentModel.DataObjectMethodType.[Select], false)>  _
    Public Overloads Overridable Function GetMaterial(ByVal line As Byte) As prodsum.DateTableDataTable 
      Me.Adapter.SelectCommand = Me.CommandCollection(1)
      Me.Adapter.SelectCommand.Parameters(0).Value = CType(line,Byte)
      Dim dataTable As prodsum.DateTableDataTable = New prodsum.DateTableDataTable
      Me.Adapter.Fill(dataTable)
      Return dataTable
    End Function

    Nothing but something

Answers

  • Wednesday, March 10, 2010 4:10 PM
     
     Answered
    Visual Basic

    Imports System.Reflection

    Module Module1

        Sub Main()
            InvokeMethod()
            Console.ReadLine()
        End Sub

        Sub InvokeMethod()

            Dim instance As Class1 = New Class1()
            Dim args As Object() = Nothing
            args = New Object(0) {"data"} ' comment out this line to invoke other method.
            Dim invoker As Type = instance.GetType()
            invoker.InvokeMember( _
                "MethodToInvoke", _
                BindingFlags.Public Or BindingFlags.Instance Or BindingFlags.InvokeMethod, _
                Nothing, _
                instance, _
                args)
            Return
        End Sub

    End Module

    Class Class1
        Sub MethodToInvoke()
            Console.WriteLine("Method_01 has been invoked through Reflection.")
        End Sub
        Sub MethodToInvoke(ByVal obj As Object)
            Console.WriteLine("Method_02 has been invoked through Reflection.")
        End Sub
    End Class


    Mark the best replies as answers. "Fooling computers since 1971."
    • Marked As Answer by goldbishop Wednesday, March 10, 2010 4:52 PM
    •  
  • Wednesday, March 10, 2010 4:59 PM
     
     Answered Has Code
    just to be clear here is the final code and worked perfectly...I should just PM you Rude next time ;) Thank you as well Mario for advising me on the potential errors that were to come up as you stated.

    Public Shared Function CreateInstance(ByVal [type] As Type, ByVal [class] As String, ByVal args() As Object) As Object
      Dim ____ As Reflection.Assembly = Reflection.Assembly.GetAssembly([type])
      Try
        For Each t As Type In ____.GetTypes
          If t.IsClass = True Then
            If t.FullName.EndsWith("." + [class]) Then
              Dim con() As Reflection.ConstructorInfo = t.GetConstructors
              For Each constr As Reflection.ConstructorInfo In con
                If constr.GetParameters.Length = args.Length Then
                  Return constr.Invoke(args)
                End If
              Next
            End If
          End If
        Next
        Return Nothing
      Catch ex As Exception
        Throw New System.Exception("could not create instance ---->" + [class])
        Return Nothing
      End Try
    End Function
    
    Public Shared Function InvokeMethod(Of T)(ByVal typeName As ComponentModel.Component, ByVal methodName As String, ByVal param() As Object) As T
      'Get the actual classes name for instantiation
      Dim [class] As String = typeName.ToString.Substring(typeName.ToString.LastIndexOf(".") + 1)
      'create an instance of the object of typeName by its class alone
      Dim instance As Object = CreateInstance(typeName.GetType, [class], New Object() {})
      'get the type of the object
      Dim invoker As Type = instance.GetType
      Dim result As Object
      result = invoker.InvokeMember(methodName, Reflection.BindingFlags.Public Or Reflection.BindingFlags.Instance Or Reflection.BindingFlags.InvokeMethod, Nothing, instance, param)
      Return CType(result, T)
    End Function
    The CreateInstance method was a code copy from another site, go here
    Nothing but something
    • Marked As Answer by goldbishop Wednesday, March 10, 2010 5:42 PM
    •  

All Replies

  • Tuesday, March 09, 2010 8:36 PM
     
     Proposed Answer
    You passed a null value, Nothing, as the object instance on which to invoke the method. 
    You must call an instance method, not a static or shared method.

    InvokeMember(String, BindingFlags, Binder, Object, Object [] )


    Rudy  =8^D

    Mark the best replies as answers. "Fooling computers since 1971."
    • Proposed As Answer by Alex Skalozub Wednesday, March 10, 2010 2:14 PM
    •  
  • Tuesday, March 09, 2010 8:45 PM
     
     

    A NullReferenceException in that context probably indicates that the type does not exist (what you store in calledType). Make sure that the type is spelled and cased correctly, and that it is fully qualified.

    Once you fix that, though, you are going to get the exception (a TargetException this time) that Rudy refers to, so you better fix that too...

    HTH
    --mc

    • Proposed As Answer by Rudedog2MVP Tuesday, March 09, 2010 8:59 PM
    • Unproposed As Answer by goldbishop Wednesday, March 10, 2010 2:02 PM
    •  
  • Wednesday, March 10, 2010 2:01 PM
     
     

    Seems that DataAdapters are not Types.  As you mentioned, the problem was in the Instance Object not being passed.

    I tried several variations but was unable to get a Type reference to my TableAdapter that holds the Method.

    Everything is Cased correctly.  But after i posted this and several hours of breakpoints :( it is ultimately failing at the calledType line.

    I would assume then that a TableAdapter is not a Type but an Object only and as such can not be Type'd?

    Any ideas on how to incorporate this type of logic on a non-Type'd object without having to code for each logical pattern?


    Nothing but something
  • Wednesday, March 10, 2010 2:23 PM
     
      Has Code
    Ok finally got the NullReferenceException removed by changing the typeName type from String to Component as such.

    Public Shared Function InvokeMethod(Of T)(ByVal typeName As ComponentModel.Component, ByVal methodName As String, ByVal param() As Object) As T
    

    And as you called it, i am getting the MissingMethodException. 

    The new InvokeMember method now is:

    result = calledType.InvokeMember(methodName, Reflection.BindingFlags.Public Or Reflection.BindingFlags.DeclaredOnly Or Reflection.BindingFlags.InvokeMethod, Nothing, typeName, param)
    
    For sake of consistency, i am trying to call the ByShift method and its declaration is:
    <Global.System.Diagnostics.DebuggerNonUserCodeAttribute(),  _
    Global.System.ComponentModel.Design.HelpKeywordAttribute("vs.data.TableAdapter"),  _
    Global.System.ComponentModel.DataObjectMethodAttribute(Global.System.ComponentModel.DataObjectMethodType.[Select], false)>  _
    Public Overloads Overridable Function GetProductionByShift(ByVal line As Byte, ByVal shift As Byte) As prodsum.DateTableDataTable
      Me.Adapter.SelectCommand = Me.CommandCollection(3)
      Me.Adapter.SelectCommand.Parameters(0).Value = CType(line,Byte)
      Me.Adapter.SelectCommand.Parameters(1).Value = CType(shift,Byte)
      Dim dataTable As prodsum.DateTableDataTable = New prodsum.DateTableDataTable
      Me.Adapter.Fill(dataTable)
      Return dataTable
    End Function

    And yes most of this was auto-generated while i designed the XSD.
    Nothing but something
  • Wednesday, March 10, 2010 2:42 PM
     
      Has Code
    Did a little debug checking now that i can actually invoke the type.

    Boolean get_ClearBeforeFill()
    Void set_ClearBeforeFill(Boolean)
    DateTableDataTable GetProduction(Byte)
    DateTableDataTable GetMaterial(Byte)
    DateTableDataTable GetMaterialByShift(Byte, System.Nullable`1[System.Byte])
    DateTableDataTable GetProductionByShift(Byte, Byte)
    DateTableDataTable GetScrap(Byte)
    DateTableDataTable GetScrapByShift(Byte, System.Nullable`1[System.Byte])
    Void add_Disposed(System.EventHandler)
    Void remove_Disposed(System.EventHandler)
    System.ComponentModel.ISite get_Site()
    Void set_Site(System.ComponentModel.ISite)
    Void Dispose()
    System.ComponentModel.IContainer get_Container()
    System.String ToString()
    System.Object GetLifetimeService()
    System.Object InitializeLifetimeService()
    System.Runtime.Remoting.ObjRef CreateObjRef(System.Type)
    Boolean Equals(System.Object)
    Int32 GetHashCode()
    System.Type GetType()
    This is the full mthods list available to the Type i am trying to get from.  I see the two methods that have Nullable types and will be fixing that soon, but otherwise this is exactly what should be here as far as i care.
    Nothing but something
  • Wednesday, March 10, 2010 2:43 PM
     
     

    The message suggests that you are providing an instance object of a type that lacks the method you are trying to invoke.  What type contains the method you are trying to invoke?  That is the type that is required in the place of where you are using "typeName".

    What do mean a TableAdapter is not a type?  Sure it is.  You should be able to see it in your Object Browser Window of your project.  Don't ignore Mario's advice, either.

    Rudy  =8^D
    Mark the best replies as answers. "Fooling computers since 1971."
  • Wednesday, March 10, 2010 2:52 PM
     
      Has Code
    I havent ignored the advice...actually his got me thinking of a different approach

    i changed the typeName type from String to Component, to correctly obtain the type reference.  Hence the Vote+1 ;)

    Seems their reply system is a little messed up atm, so sorry for the unordered replies.  I did a Debug.WriteLine iteration on the Methods that are available through the Type object and its there even with the Parameter set i am passing

    Here is the core information:

    param() = {Byte, Byte}
    methodName = "GetProductionByShift"
    typeName = prodsum.prodsumTableAdapters.DateTableTableAdapter
    Everything is correct, maybe the InvokeMember use is incorrect, but otherwise everything is going well, just cant seem to get the TableAdapter to call the method, unless i need to involve another step before the InvokeMember method.  I tried using the Assembly call for the Class name to get a class object reference but it didnt work either.  I am expanding my knowledge of the .Net framework with this little dig of mine.
    Nothing but something
  • Wednesday, March 10, 2010 2:58 PM
     
     
    What type contains the method you are trying to invoke?  TableAdapter? 
    That is the type that is required in the place of where you are using "typeName".
    Mark the best replies as answers. "Fooling computers since 1971."
  • Wednesday, March 10, 2010 3:18 PM
     
      Has Code
    Here's an example for a Console Application.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Reflection;

    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                InvokeMethod();
            }
            private static void InvokeMethod()
            {
                Class1 instance = new Class1();
                Object[] args = null;
                args = new Object[] { "data" };  // comment this line out to call other method!
                Type invoker = instance.GetType();
                invoker.InvokeMember(
                    "MethodToInvoke",
                    BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod,
                    null,
                    instance,
                    args);
                Console.ReadLine();
            }
        }
    }

        public class Class1
        {
            public void MethodToInvoke()
            {
                Console.WriteLine("Method_01 has been invoked through Reflection.");
            }
            public void MethodToInvoke(object obj)
            {
                Console.WriteLine("Method_02 has been invoked through Reflection.");
            }
        }



    Hope this helps.

    Rudy  =8^D
    Mark the best replies as answers. "Fooling computers since 1971."
  • Wednesday, March 10, 2010 4:10 PM
     
     Answered
    Visual Basic

    Imports System.Reflection

    Module Module1

        Sub Main()
            InvokeMethod()
            Console.ReadLine()
        End Sub

        Sub InvokeMethod()

            Dim instance As Class1 = New Class1()
            Dim args As Object() = Nothing
            args = New Object(0) {"data"} ' comment out this line to invoke other method.
            Dim invoker As Type = instance.GetType()
            invoker.InvokeMember( _
                "MethodToInvoke", _
                BindingFlags.Public Or BindingFlags.Instance Or BindingFlags.InvokeMethod, _
                Nothing, _
                instance, _
                args)
            Return
        End Sub

    End Module

    Class Class1
        Sub MethodToInvoke()
            Console.WriteLine("Method_01 has been invoked through Reflection.")
        End Sub
        Sub MethodToInvoke(ByVal obj As Object)
            Console.WriteLine("Method_02 has been invoked through Reflection.")
        End Sub
    End Class


    Mark the best replies as answers. "Fooling computers since 1971."
    • Marked As Answer by goldbishop Wednesday, March 10, 2010 4:52 PM
    •  
  • Wednesday, March 10, 2010 4:13 PM
     
     
    So i will need to do an Assembly Reflection to get an instance of the class built so i can pass that instance through the InvokeMember method?
    Nothing but something
  • Wednesday, March 10, 2010 4:59 PM
     
     Answered Has Code
    just to be clear here is the final code and worked perfectly...I should just PM you Rude next time ;) Thank you as well Mario for advising me on the potential errors that were to come up as you stated.

    Public Shared Function CreateInstance(ByVal [type] As Type, ByVal [class] As String, ByVal args() As Object) As Object
      Dim ____ As Reflection.Assembly = Reflection.Assembly.GetAssembly([type])
      Try
        For Each t As Type In ____.GetTypes
          If t.IsClass = True Then
            If t.FullName.EndsWith("." + [class]) Then
              Dim con() As Reflection.ConstructorInfo = t.GetConstructors
              For Each constr As Reflection.ConstructorInfo In con
                If constr.GetParameters.Length = args.Length Then
                  Return constr.Invoke(args)
                End If
              Next
            End If
          End If
        Next
        Return Nothing
      Catch ex As Exception
        Throw New System.Exception("could not create instance ---->" + [class])
        Return Nothing
      End Try
    End Function
    
    Public Shared Function InvokeMethod(Of T)(ByVal typeName As ComponentModel.Component, ByVal methodName As String, ByVal param() As Object) As T
      'Get the actual classes name for instantiation
      Dim [class] As String = typeName.ToString.Substring(typeName.ToString.LastIndexOf(".") + 1)
      'create an instance of the object of typeName by its class alone
      Dim instance As Object = CreateInstance(typeName.GetType, [class], New Object() {})
      'get the type of the object
      Dim invoker As Type = instance.GetType
      Dim result As Object
      result = invoker.InvokeMember(methodName, Reflection.BindingFlags.Public Or Reflection.BindingFlags.Instance Or Reflection.BindingFlags.InvokeMethod, Nothing, instance, param)
      Return CType(result, T)
    End Function
    The CreateInstance method was a code copy from another site, go here
    Nothing but something
    • Marked As Answer by goldbishop Wednesday, March 10, 2010 5:42 PM
    •