動態載入和使用類型Dynamically Loading and Using Types

反映會提供語言編譯器所使用的基礎結構,以實作隱含晚期繫結。Reflection provides infrastructure used by language compilers to implement implicit late binding. 繫結是尋找對應至唯一指定的類型宣告 (也就是實作) 的程序。Binding is the process of locating the declaration (that is, the implementation) that corresponds to a uniquely specified type. 當此程序發生在執行階段,而不是在編譯時期時,它稱為晚期繫結。When this process occurs at run time rather than at compile time, it is called late binding. Visual Basic 可讓您在程式碼內使用隱含晚期繫結;Visual Basic 編譯器會呼叫 Helper 方法,它會使用反映來取得物件類型。Visual Basic allows you to use implicit late binding in your code; the Visual Basic compiler calls a helper method that uses reflection to obtain the object type. 傳遞至 helper 方法的引數會導致在執行階段叫用適當的方法。The arguments passed to the helper method cause the appropriate method to be invoked at run time. 這些引數是在其上叫用方法的執行個體 (物件)、被叫用方法的名稱 (字串),以及傳遞給被叫用方法的引數 (物件陣列)。These arguments are the instance (an object) on which to invoke the method, the name of the invoked method (a string), and the arguments passed to the invoked method (an array of objects).

在下列範例中,Visual Basic 編譯器會隱含地使用反映,對一個在編譯階段不知道其類型的物件呼叫方法。In the following example, the Visual Basic compiler uses reflection implicitly to call a method on an object whose type is not known at compile time. HelloWorld 類別具有 PrintHello 方法,它會列印出 "Hello World" 並串連傳遞給 PrintHello 方法的部分文字。A HelloWorld class has a PrintHello method that prints out "Hello World" concatenated with some text that is passed to the PrintHello method. 在此範例中呼叫的 PrintHello 方法實際上是 Type.InvokeMember;Visual Basic 程式碼允許叫用 PrintHello 方法,就彷彿已在編譯階段知道物件 (helloObj) 的類型 (早期繫結),而不是執行階段知道 (晚期繫結)。The PrintHello method called in this example is actually a Type.InvokeMember; the Visual Basic code allows the PrintHello method to be invoked as if the type of the object (helloObj) were known at compile time (early binding) rather than at run time (late binding).

Module Hello  
    Sub Main()  
        ' Sets up the variable.  
        Dim helloObj As Object  
        ' Creates the object.  
        helloObj = new HelloWorld()  
        ' Invokes the print method as if it was early bound  
        ' even though it is really late bound.  
        helloObj.PrintHello("Visual Basic Late Bound")  
    End Sub  
End Module  

自訂繫結Custom Binding

除了編譯器隱含地用來進行晚期繫結,反映也可明確地用於程式碼,來完成晚期繫結。In addition to being used implicitly by compilers for late binding, reflection can be used explicitly in code to accomplish late binding.

Common Language Runtime 支援多種程式設計語言,而這些語言的繫結規則不同。The common language runtime supports multiple programming languages, and the binding rules of these languages differ. 在早期繫結案例中,程式碼產生器可以完全控制這個繫結。In the early-bound case, code generators can completely control this binding. 不過,在透過反映的晚期繫結中,繫結必須受自訂繫結控制。However, in late binding through reflection, binding must be controlled by customized binding. Binder 類別會提供成員選取和叫用的自訂控制。The Binder class provides custom control of member selection and invocation.

您可以使用自訂繫結,在執行階段載入組件、取得該組件中的類型相關資訊、指定您要的類型,然後對該類型叫用方法或存取欄位或屬性。Using custom binding, you can load an assembly at run time, obtain information about types in that assembly, specify the type that you want, and then invoke methods or access fields or properties on that type. 這個技術非常有用,如果您在編譯時期不知道物件的類型,例如當物件類型取決於使用者輸入之時。This technique is useful if you do not know an object's type at compile time, such as when the object type is dependent on user input.

下列範例將示範簡單的自訂繫結,它不提供任何引數類型轉換。The following example demonstrates a simple custom binder that provides no argument type conversion. Simple_Type.dll 的程式碼在主要範例之前。Code for Simple_Type.dll precedes the main example. 請務必建置 Simple_Type.dll,然後在建置階段的專案中包含對它的參考。Be sure to build Simple_Type.dll and then include a reference to it in the project at build time.

// Code for building SimpleType.dll.
using namespace System;
using namespace System::Reflection;
using namespace System::Globalization;

namespace Simple_Type
{
    public ref class MySimpleClass
    {
    public:
        void MyMethod(String^ str, int i)
        {
            Console::WriteLine("MyMethod parameters: {0}, {1}", str, i);
        }

        void MyMethod(String^ str, int i, int j)
        {
            Console::WriteLine("MyMethod parameters: {0}, {1}, {2}",
                str, i, j);
        }
    };
}

using namespace Simple_Type;

namespace Custom_Binder
{
    // ****************************************************
    //  A simple custom binder that provides no
    //  argument type conversion.
    // ****************************************************
    public ref class MyCustomBinder : Binder
    {
    public:
        virtual MethodBase^ BindToMethod(
            BindingFlags bindingAttr,
            array<MethodBase^>^ match,
            array<Object^>^% args,
            array<ParameterModifier>^ modifiers,
            CultureInfo^ culture,
            array<String^>^ names,
            Object^% state) override
        {
            if (match == nullptr)
            {
                throw gcnew ArgumentNullException("match");
            }
            // Arguments are not being reordered.
            state = nullptr;
            // Find a parameter match and return the first method with
            // parameters that match the request.
            for each (MethodBase^ mb in match)
            {
                array<ParameterInfo^>^ parameters = mb->GetParameters();

                if (ParametersMatch(parameters, args))
                {
                    return mb;
                }
            }
            return nullptr;
        }

        virtual FieldInfo^ BindToField(BindingFlags bindingAttr,
            array<FieldInfo^>^ match, Object^ value, CultureInfo^ culture) override
        {
            if (match == nullptr)
            {
                throw gcnew ArgumentNullException("match");
            }
            for each (FieldInfo^ fi in match)
            {
                if (fi->GetType() == value->GetType())
                {
                    return fi;
                }
            }
            return nullptr;
        }

        virtual MethodBase^ SelectMethod(
            BindingFlags bindingAttr,
            array<MethodBase^>^ match,
            array<Type^>^ types,
            array<ParameterModifier>^ modifiers) override
        {
            if (match == nullptr)
            {
                throw gcnew ArgumentNullException("match");
            }

            // Find a parameter match and return the first method with
            // parameters that match the request.
            for each (MethodBase^ mb in match)
            {
                array<ParameterInfo^>^ parameters = mb->GetParameters();
                if (ParametersMatch(parameters, types))
                {
                    return mb;
                }
            }

            return nullptr;
        }

        virtual PropertyInfo^ SelectProperty(
            BindingFlags bindingAttr,
            array<PropertyInfo^>^ match,
            Type^ returnType,
            array<Type^>^ indexes,
            array<ParameterModifier>^ modifiers) override
        {
            if (match == nullptr)
            {
                throw gcnew ArgumentNullException("match");
            }
            for each (PropertyInfo^ pi in match)
            {
                if (pi->GetType() == returnType &&
                    ParametersMatch(pi->GetIndexParameters(), indexes))
                {
                    return pi;
                }
            }
            return nullptr;
        }

        virtual Object^ ChangeType(
            Object^ value,
            Type^ myChangeType,
            CultureInfo^ culture) override
        {
            try
            {
                Object^ newType;
                newType = Convert::ChangeType(value, myChangeType);
                return newType;
            }
            // Throw an InvalidCastException if the conversion cannot
            // be done by the Convert.ChangeType method.
            catch (InvalidCastException^)
            {
                return nullptr;
            }
        }

        virtual void ReorderArgumentArray(array<Object^>^% args,
            Object^ state) override
        {
            // No operation is needed here because BindToMethod does not
            // reorder the args array. The most common implementation
            // of this method is shown below.

            // ((BinderState^)state).args.CopyTo(args, 0);
        }

        // Returns true only if the type of each object in a matches
        // the type of each corresponding object in b.
    private:
        bool ParametersMatch(array<ParameterInfo^>^ a, array<Object^>^ b)
        {
            if (a->Length != b->Length)
            {
                return false;
            }
            for (int i = 0; i < a->Length; i++)
            {
                if (a[i]->ParameterType != b[i]->GetType())
                {
                    return false;
                }
            }
            return true;
        }

        // Returns true only if the type of each object in a matches
        // the type of each corresponding entry in b.
        bool ParametersMatch(array<ParameterInfo^>^ a, array<Type^>^ b)
        {
            if (a->Length != b->Length)
            {
                return false;
            }
            for (int i = 0; i < a->Length; i++)
            {
                if (a[i]->ParameterType != b[i])
                {
                    return false;
                }
            }
            return true;
        }
    };

    public ref class MyMainClass
    {
    public:
        static void Main()
        {
            // Get the type of MySimpleClass.
            Type^ myType = MySimpleClass::typeid;

            // Get an instance of MySimpleClass.
            MySimpleClass^ myInstance = gcnew MySimpleClass();
            MyCustomBinder^ myCustomBinder = gcnew MyCustomBinder();

            // Get the method information for the particular overload
            // being sought.
            MethodInfo^ myMethod = myType->GetMethod("MyMethod",
                BindingFlags::Public | BindingFlags::Instance,
                myCustomBinder, gcnew array<Type^> {String::typeid,
                int::typeid}, nullptr);
            Console::WriteLine(myMethod->ToString());

            // Invoke the overload.
            myType->InvokeMember("MyMethod", BindingFlags::InvokeMethod,
                myCustomBinder, myInstance,
                gcnew array<Object^> {"Testing...", (int)32});
        }
    };
}

int main()
{
    Custom_Binder::MyMainClass::Main();
}
// Code for building SimpleType.dll.
using System;
using System.Reflection;
using System.Globalization;
using Simple_Type;

namespace Simple_Type
{
    public class MySimpleClass
    {
        public void MyMethod(string str, int i)
        {
            Console.WriteLine("MyMethod parameters: {0}, {1}", str, i);
        }

        public void MyMethod(string str, int i, int j)
        {
            Console.WriteLine("MyMethod parameters: {0}, {1}, {2}",
                str, i, j);
        }
    }
}

namespace Custom_Binder
{
    class MyMainClass
    {
        static void Main()
        {
            // Get the type of MySimpleClass.
            Type myType = typeof(MySimpleClass);

            // Get an instance of MySimpleClass.
            MySimpleClass myInstance = new MySimpleClass();
            MyCustomBinder myCustomBinder = new MyCustomBinder();

            // Get the method information for the particular overload 
            // being sought.
            MethodInfo myMethod = myType.GetMethod("MyMethod", 
                BindingFlags.Public | BindingFlags.Instance,
                myCustomBinder, new Type[] {typeof(string), 
                typeof(int)}, null);
            Console.WriteLine(myMethod.ToString());
            
            // Invoke the overload.
            myType.InvokeMember("MyMethod", BindingFlags.InvokeMethod, 
                myCustomBinder, myInstance,
                new Object[] {"Testing...", (int)32});
        }
    }

    // ****************************************************
    //  A simple custom binder that provides no
    //  argument type conversion.
    // ****************************************************
    class MyCustomBinder : Binder
    {
        public override MethodBase BindToMethod(
            BindingFlags bindingAttr,
            MethodBase[] match,
            ref object[] args,
            ParameterModifier[] modifiers,
            CultureInfo culture,
            string[] names,
            out object state)
        {
            if (match == null)
            {
                throw new ArgumentNullException("match");
            }
            // Arguments are not being reordered.
            state = null;
            // Find a parameter match and return the first method with
            // parameters that match the request.
            foreach (MethodBase mb in match)
            {
                ParameterInfo[] parameters = mb.GetParameters();

                if (ParametersMatch(parameters, args))
                {
                    return mb;
                }
            }
            return null;
        }

        public override FieldInfo BindToField(BindingFlags bindingAttr, 
            FieldInfo[] match, object value, CultureInfo culture)
        {
            if (match == null)
            {
                throw new ArgumentNullException("match");
            }
            foreach (FieldInfo fi in match)
            {
                if (fi.GetType() == value.GetType())
                {
                    return fi;
                }
            }
            return null;
        }

        public override MethodBase SelectMethod(
            BindingFlags bindingAttr,
            MethodBase[] match,
            Type[] types,
            ParameterModifier[] modifiers)
        {
            if (match == null)
            {
                throw new ArgumentNullException("match");
            }

            // Find a parameter match and return the first method with
            // parameters that match the request.
            foreach (MethodBase mb in match)
            {
                ParameterInfo[] parameters = mb.GetParameters();
                if (ParametersMatch(parameters, types))
                {
                    return mb;
                }
            }

            return null;
        }

        public override PropertyInfo SelectProperty(
            BindingFlags bindingAttr,
            PropertyInfo[] match,
            Type returnType,
            Type[] indexes,
            ParameterModifier[] modifiers)
        {
            if (match == null)
            {
                throw new ArgumentNullException("match");
            }
            foreach (PropertyInfo pi in match)
            {
                if (pi.GetType() == returnType &&
                    ParametersMatch(pi.GetIndexParameters(), indexes))
                {
                    return pi;
                }
            }
            return null;
        }

        public override object ChangeType(
            object value,
            Type myChangeType,
            CultureInfo culture)
        {
            try
            {
                object newType;
                newType = Convert.ChangeType(value, myChangeType);
                return newType;
            }
            // Throw an InvalidCastException if the conversion cannot
            // be done by the Convert.ChangeType method.
            catch (InvalidCastException)
            {
                return null;
            }
        }

        public override void ReorderArgumentArray(ref object[] args,
            object state)
        {
            // No operation is needed here because BindToMethod does not
            // reorder the args array. The most common implementation
            // of this method is shown below.

            // ((BinderState)state).args.CopyTo(args, 0);
        }

        // Returns true only if the type of each object in a matches
        // the type of each corresponding object in b.
        private bool ParametersMatch(ParameterInfo[] a, object[] b)
        {
            if (a.Length != b.Length)
            {
                return false;
            }
            for (int i = 0; i < a.Length; i++)
            {
                if (a[i].ParameterType != b[i].GetType())
                {
                    return false;
                }
            }
            return true;
        }

        // Returns true only if the type of each object in a matches
        // the type of each corresponding entry in b.
        private bool ParametersMatch(ParameterInfo[] a, Type[] b)
        {
            if (a.Length != b.Length)
            {
                return false;
            }
            for (int i = 0; i < a.Length; i++)
            {
                if (a[i].ParameterType != b[i])
                {
                    return false;
                }
            }
            return true;
        }
    }
}
' Code for building SimpleType.dll.
Imports System.Reflection
Imports System.Globalization
Imports Simple_Type

Namespace Simple_Type
    Public Class MySimpleClass
        Public Sub MyMethod(str As String, i As Integer)
            Console.WriteLine("MyMethod parameters: {0}, {1}", str, i)
        End Sub

        Public Sub MyMethod(str As String, i As Integer, j As Integer)
            Console.WriteLine("MyMethod parameters: {0}, {1}, {2}",
                str, i, j)
        End Sub
    End Class
End Namespace

Namespace Custom_Binder
    Class MyMainClass
        Shared Sub Main()
            ' Get the type of MySimpleClass.
            Dim myType As Type = GetType(MySimpleClass)

            ' Get an instance of MySimpleClass.
            Dim myInstance As New MySimpleClass()
            Dim myCustomBinder As New MyCustomBinder()

            ' Get the method information for the particular overload
            ' being sought.
            Dim myMethod As MethodInfo = myType.GetMethod("MyMethod",
                BindingFlags.Public Or BindingFlags.Instance,
                myCustomBinder, New Type() {GetType(String),
                GetType(Integer)}, Nothing)
            Console.WriteLine(myMethod.ToString())

            ' Invoke the overload.
            myType.InvokeMember("MyMethod", BindingFlags.InvokeMethod,
                myCustomBinder, myInstance,
                New Object() {"Testing...", CInt(32)})
        End Sub
    End Class

    ' ****************************************************
    '  A simple custom binder that provides no
    '  argument type conversion.
    ' ****************************************************
    Class MyCustomBinder
        Inherits Binder

        Public Overrides Function BindToMethod(bindingAttr As BindingFlags,
            match() As MethodBase, ByRef args As Object(),
            modIfiers() As ParameterModIfier, culture As CultureInfo,
            names() As String, ByRef state As Object) As MethodBase

            If match is Nothing Then
                Throw New ArgumentNullException("match")
            End If
            ' Arguments are not being reordered.
            state = Nothing
            ' Find a parameter match and return the first method with
            ' parameters that match the request.
            For Each mb As MethodBase in match
                Dim parameters() As ParameterInfo = mb.GetParameters()

                If ParametersMatch(parameters, args) Then
                    Return mb
                End If
            Next mb
            Return Nothing
        End Function

        Public Overrides Function BindToField(bindingAttr As BindingFlags,
            match() As FieldInfo, value As Object, culture As CultureInfo) As FieldInfo
            If match Is Nothing
                Throw New ArgumentNullException("match")
            End If
            For Each fi As FieldInfo in match
                If fi.GetType() = value.GetType() Then
                    Return fi
                End If
            Next fi
            Return Nothing
        End Function

        Public Overrides Function SelectMethod(bindingAttr As BindingFlags,
            match() As MethodBase, types() As Type,
            modifiers() As ParameterModifier) As MethodBase

            If match Is Nothing Then
                Throw New ArgumentNullException("match")
            End If

            ' Find a parameter match and return the first method with
            ' parameters that match the request.
            For Each mb As MethodBase In match
                Dim parameters() As ParameterInfo = mb.GetParameters()
                If ParametersMatch(parameters, types) Then
                    Return mb
                End If
            Next mb

            Return Nothing
        End Function

        Public Overrides Function SelectProperty(
            bindingAttr As BindingFlags, match() As PropertyInfo,
            returnType As Type, indexes() As Type,
            modIfiers() As ParameterModIfier) As PropertyInfo

            If match Is Nothing Then
                Throw New ArgumentNullException("match")
            End If
            For Each pi As PropertyInfo In match
                If pi.GetType() = returnType And
                    ParametersMatch(pi.GetIndexParameters(), indexes) Then
                    Return pi
                End If
            Next pi
            Return Nothing
        End Function

        Public Overrides Function ChangeType(
            value As Object,
            myChangeType As Type,
            culture As CultureInfo) As Object

            Try
                Dim newType As Object
                newType = Convert.ChangeType(value, myChangeType)
                Return newType
            ' Throw an InvalidCastException If the conversion cannot
            ' be done by the Convert.ChangeType method.
            Catch
                Return Nothing
            End Try
        End Function

        Public Overrides Sub ReorderArgumentArray(ByRef args() As Object, state As Object)
            ' No operation is needed here because BindToMethod does not
            ' reorder the args array. The most common implementation
            ' of this method is shown below.

            ' ((BinderState)state).args.CopyTo(args, 0)
        End Sub

        ' Returns true only If the type of each object in a matches
        ' the type of each corresponding object in b.
        Private Overloads Function ParametersMatch(a() As ParameterInfo, b() As Object) As Boolean
            If a.Length <> b.Length Then
                Return false
            End If
            For i As Integer = 0 To a.Length - 1
                If a(i).ParameterType <> b(i).GetType() Then
                    Return false
                End If
            Next i
            Return true
        End Function

        ' Returns true only If the type of each object in a matches
        ' the type of each corresponding enTry in b.
        Private Overloads Function ParametersMatch(a() As ParameterInfo,
            b() As Type) As Boolean

            If a.Length <> b.Length Then
                Return false
            End If
            For i As Integer = 0 To a.Length - 1
                If a(i).ParameterType <> b(i)
                    Return false
                End If
            Next
            Return true
        End Function
    End Class
End Namespace

InvokeMember 和 CreateInstanceInvokeMember and CreateInstance

使用 Type.InvokeMember 來叫用類型的成員。Use Type.InvokeMember to invoke a member of a type. 各種類別的 CreateInstance 方法,例如 Activator.CreateInstanceAssembly.CreateInstance,是 InvokeMember 的特殊形式,會建立指定類型的新執行個體。The CreateInstance methods of various classes, such as Activator.CreateInstance and Assembly.CreateInstance, are specialized forms of InvokeMember that create new instances of the specified type. Binder 類別用來在這些方法中進行多載解析和引數強制型轉。The Binder class is used for overload resolution and argument coercion in these methods.

下列範例顯示引數強制型轉 (類型轉換) 和成員選取的三種可能組合。The following example shows the three possible combinations of argument coercion (type conversion) and member selection. 案例 1 中不需要任何引數強制型轉或成員選取。In Case 1, no argument coercion or member selection is needed. 案例 2 中只需要成員選取。In Case 2, only member selection is needed. 案例 3 中只需要引數強制型轉。In Case 3, only argument coercion is needed.

public ref class CustomBinderDriver
{
public:
    static void Main()
    {
        Type^ t = CustomBinderDriver::typeid;
        CustomBinder^ binder = gcnew CustomBinder();
        BindingFlags flags = BindingFlags::InvokeMethod | BindingFlags::Instance |
            BindingFlags::Public | BindingFlags::Static;
        array<Object^>^ args;

        // Case 1. Neither argument coercion nor member selection is needed.
        args = gcnew array<Object^> {};
        t->InvokeMember("PrintBob", flags, binder, nullptr, args);

        // Case 2. Only member selection is needed.
        args = gcnew array<Object^> {42};
        t->InvokeMember("PrintValue", flags, binder, nullptr, args);

        // Case 3. Only argument coercion is needed.
        args = gcnew array<Object^> {"5.5"};
        t->InvokeMember("PrintNumber", flags, binder, nullptr, args);
    }

    static void PrintBob()
    {
        Console::WriteLine("PrintBob");
    }

    static void PrintValue(long value)
    {
        Console::WriteLine("PrintValue({0})", value);
    }

    static void PrintValue(String^ value)
    {
        Console::WriteLine("PrintValue\"{0}\")", value);
    }

    static void PrintNumber(double value)
    {
        Console::WriteLine("PrintNumber ({0})", value);
    }
};

int main()
{
    CustomBinderDriver::Main();
}
public class CustomBinderDriver
{
    public static void Main()
    {
        Type t = typeof(CustomBinderDriver);
        CustomBinder binder = new CustomBinder();
        BindingFlags flags = BindingFlags.InvokeMethod | BindingFlags.Instance |
            BindingFlags.Public | BindingFlags.Static;
        object[] args;

        // Case 1. Neither argument coercion nor member selection is needed.
        args = new object[] {};
        t.InvokeMember("PrintBob", flags, binder, null, args);

        // Case 2. Only member selection is needed.
        args = new object[] {42};
        t.InvokeMember("PrintValue", flags, binder, null, args);

        // Case 3. Only argument coercion is needed.
        args = new object[] {"5.5"};
        t.InvokeMember("PrintNumber", flags, binder, null, args);
    }

    public static void PrintBob()
    {
        Console.WriteLine("PrintBob");
    }

    public static void PrintValue(long value)
    {
        Console.WriteLine("PrintValue({0})", value);
    }
    
    public static void PrintValue(string value)
    {
        Console.WriteLine("PrintValue\"{0}\")", value);
    }

    public static void PrintNumber(double value)
    {
        Console.WriteLine("PrintNumber ({0})", value);
    }
}
Public Class CustomBinderDriver
    Public Shared Sub Main()
        Dim t As Type = GetType(CustomBinderDriver)
        Dim binder As New CustomBinder()
        Dim flags As BindingFlags = BindingFlags.InvokeMethod Or BindingFlags.Instance Or
            BindingFlags.Public Or BindingFlags.Static
        Dim args() As Object

        ' Case 1. Neither argument coercion nor member selection is needed.
        args = New object() {}
        t.InvokeMember ("PrintBob", flags, binder, Nothing, args)

        ' Case 2. Only member selection is needed.
        args = New object() {42}
        t.InvokeMember ("PrintValue", flags, binder, Nothing, args)

        ' Case 3. Only argument coercion is needed.
        args = New object() {"5.5"}
        t.InvokeMember("PrintNumber", flags, binder, Nothing, args)
    End Sub

    Public Shared Sub PrintBob()
        Console.WriteLine ("PrintBob")
    End Sub

    Public Shared Sub PrintValue(value As Long)
        Console.WriteLine("PrintValue ({0})", value)
    End Sub

    Public Shared Sub PrintValue(value As String)
        Console.WriteLine("PrintValue ""{0}"")", value)
    End Sub

    Public Shared Sub PrintNumber(value As Double)
        Console.WriteLine("PrintNumber ({0})", value)
    End Sub
End Class

有多個相同名稱的成員可用時,需要多載解析。Overload resolution is needed when more than one member with the same name is available. Binder.BindToMethodBinder.BindToField 方法用來解析對單一成員的繫結。The Binder.BindToMethod and Binder.BindToField methods are used to resolve binding to a single member. Binder.BindToMethod 也透過 getset 屬性存取子提供屬性解析。Binder.BindToMethod also provides property resolution through the get and set property accessors.

BindToMethod 會傳回要叫用的 MethodBase,如果不可能進行這種叫用則傳回 null 參考 (在 Visual Basic 中為 Nothing)。BindToMethod returns the MethodBase to invoke, or a null reference (Nothing in Visual Basic) if no such invocation is possible. MethodBase 傳回值不一定要是 match 參數中所包含的其中一者,雖然這是常見的情況。The MethodBase return value need not be one of those contained in the match parameter, although that is the usual case.

有 ByRef 引數存在時,呼叫端可能會想要取回它們。When ByRef arguments are present, the caller might want to get them back. 因此,Binder 允許用戶端將引數的陣列對應回其原始形式,如果 BindToMethod 已操作引數陣列的話。Therefore, Binder allows a client to map the array of arguments back to its original form if BindToMethod has manipulated the argument array. 若要這樣做,必須向呼叫端保證,引數的順序不變。In order to do this, the caller must be guaranteed that the order of the arguments is unchanged. 依名稱傳遞引數時,Binder 會重新排列引數陣列,那也是呼叫端看到的情況。When arguments are passed by name, Binder reorders the argument array, and that is what the caller sees. 如需詳細資訊,請參閱 Binder.ReorderArgumentArrayFor more information, see Binder.ReorderArgumentArray.

可用成員的集合是在類型或任何基底類型中定義的成員。The set of available members are those members defined in the type or any base type. 如果指定 BindingFlags,則會在集合中傳回任何存取範圍的成員。If BindingFlags is specified, members of any accessibility will be returned in the set. 如果未指定 BindingFlags.NonPublic,繫結器必須強制執行存取範圍規則。If BindingFlags.NonPublic is not specified, the binder must enforce accessibility rules. 指定 PublicNonPublic 繫結旗標時,您也必須指定 InstanceStatic 繫結旗標,否則不會傳回任何成員。When specifying the Public or NonPublic binding flag, you must also specify the Instance or Static binding flag, or no members will be returned.

如果指定名稱的成員只有一個,便不需要回呼,會對該方法進行任何繫結。If there is only one member of the given name, no callback is necessary, and binding is done on that method. 程式碼範例的案例 1 將說明這一點:只有一個 PrintBob 方法可用,因此不需要回呼。Case 1 of the code example illustrates this point: Only one PrintBob method is available, and therefore no callback is needed.

如果可用的集合中有多個成員,這些方法全都會傳遞至 BindToMethod,它會選取適當的方法,並傳回它。If there is more than one member in the available set, all these methods are passed to BindToMethod, which selects the appropriate method and returns it. 在程式碼範例的案例 2 中,有兩個方法,名為 PrintValueIn Case 2 of the code example, there are two methods named PrintValue. 呼叫 BindToMethod 會選取適當的方法。The appropriate method is selected by the call to BindToMethod.

ChangeType 會執行引數強制型轉 (類型轉換),這會將實際引數轉換為所選方法的正式引數的類型。ChangeType performs argument coercion (type conversion), which converts the actual arguments to the type of the formal arguments of the selected method. 即使類型完全相符,也會為每個引數呼叫 ChangeTypeChangeType is called for every argument even if the types match exactly.

程式碼範例的案例 3 中,類型 String 的實際引數以及值 "5.5" 會傳遞至具有類型 Double 的型式引數的方法。In Case 3 of the code example, an actual argument of type String with a value of "5.5" is passed to a method with a formal argument of type Double. 叫用要成功,字串值 "5.5" 必須轉換為雙精度浮點數值。For the invocation to succeed, the string value "5.5" must be converted to a double value. ChangeType 會執行這項轉換。ChangeType performs this conversion.

ChangeType 只能執行不失真或擴展強制型轉,如下表所示。ChangeType performs only lossless or widening coercions, as shown in the following table.

來源類型Source type 目標類型Target type
任何型別Any type 基底類型Its base type
任何型別Any type 實作的介面Interface it implements
CharChar UInt16、UInt32、Int32、UInt64、Int64、Single、DoubleUInt16, UInt32, Int32, UInt64, Int64, Single, Double
ByteByte Char、UInt16、Int16、UInt32、Int32、UInt64、Int64、Single、DoubleChar, UInt16, Int16, UInt32, Int32, UInt64, Int64, Single, Double
SByteSByte Int16、Int32、Int64、Single、DoubleInt16, Int32, Int64, Single, Double
UInt16UInt16 UInt32、Int32、UInt64、Int64、Single、DoubleUInt32, Int32, UInt64, Int64, Single, Double
Int16Int16 Int32、Int64、Single、DoubleInt32, Int64, Single, Double
UInt32UInt32 UInt64、Int64、Single、DoubleUInt64, Int64, Single, Double
Int32Int32 Int64、Single、DoubleInt64, Single, Double
UInt64UInt64 Single、DoubleSingle, Double
Int64Int64 Single、DoubleSingle, Double
SingleSingle DoubleDouble
非參考類型Nonreference type 參考型別Reference type

Type 類別具有 Get 方法,使用類型 Binder 的參數來解析對特定成員的參考。The Type class has Get methods that use parameters of type Binder to resolve references to a particular member. Type.GetConstructorType.GetMethodType.GetProperty 會搜尋目前類型的特定成員,方法是提供該成員的簽章資訊。Type.GetConstructor, Type.GetMethod, and Type.GetProperty search for a particular member of the current type by providing signature information for that member. 接著回來呼叫 Binder.SelectMethodBinder.SelectProperty,選取適當方法的指定簽章資訊。Binder.SelectMethod and Binder.SelectProperty are called back on to select the given signature information of the appropriate methods.

另請參閱See also