动态加载和使用类型

反射提供语言编译器(如 Microsoft Visual Basic 2005 和 JScript)用于实现隐式后期绑定的基础结构。 绑定是查找与唯一指定的类型相对应的声明(即实现)的过程。 如果此过程是在运行时而不是在编译时发生,则称其为“后期绑定”。 利用 Visual Basic 2005,可以在代码中使用隐式后期绑定;Visual Basic 编译器会调用一个帮助器方法,该方法使用反射来获取对象类型。 传递给帮助器方法的参数有助于在运行时调用正确的方法。 这些参数包括:对其调用方法的实例(对象),被调用方法的名称(字符串),以及传递给被调用方法的参数(对象数组)。

在下面的示例中,Visual Basic 编译器使用反射隐式地对其类型在编译时未知的对象调用方法。 HelloWorld 类具有一个 PrintHello 方法,它输出与传递给 PrintHello 方法的某些文本串联的“Hello World”。 在此示例中调用的 PrintHello 方法实际上是 Type.InvokeMember;Visual Basic 代码允许按照对象 (helloObj) 的类型在编译时已知(早期绑定)而不是在运行时已知(后期绑定)的方式来调用 PrintHello 方法。

Imports System
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

自定义绑定

除了由编译器隐式地用来进行后期绑定之外,反射还可以在代码中显式地用来完成后期绑定。

公共语言运行时支持多种编程语言,但这些语言的绑定规则各不相同。 在早期绑定的情况下,代码生成器可以完全控制此绑定。 但是,当通过反射进行后期绑定时,必须用自定义绑定来控制绑定。 Binder 类提供了对成员选择和调用的自定义控制。

利用自定义绑定,您可以在运行时加载程序集,获取有关该程序集中类型的信息,然后对该类型调用方法或访问该类型的字段或属性。 如果您在编译时(例如当对象类型依赖于用户输入时)不知道对象的类型,就可以使用这种方法。

下面的示例说明不提供参数类型转换的简单的自定义联编程序。 Simple_Type.dll 的代码位于示例主体之前。 确保生成 Simple_Type.dll,然后在生成时在项目中包括对它的引用。

' Code for building SimpleType.dll.
Imports System
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
// 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.
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();
}

InvokeMember 和 CreateInstance

使用 Type.InvokeMember 可调用类型的成员。 各个类(如 System.ActivatorSystem.Reflection.Assembly)的 CreateInstance 方法是 InvokeMember 的特殊形式,它们可新建特定类型的实例。 Binder 类用于在这些方法中进行重载决策和参数强制。

下面的示例显示参数强制(类型转换)和成员选择的三种可能的组合。 在第 1 种情况中,不需要任何参数强制或成员选择。 在第 2 种情况中,只需要成员选择。 在第 3 种情况中,只需要参数强制。

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

当多个成员具有相同的名称时,将需要重载决策。 Binder.BindToMethodBinder.BindToField 方法用于解析与单个成员的绑定。 Binder.BindToMethod 还通过 getset 属性访问器提供了属性解析。

BindToMethod 返回要调用的 MethodBase;如果无法进行这种调用,则返回 null 引用(在 Visual Basic 中为 Nothing)。 虽然 MethodBase 返回值通常是 match 参数中所包含的值之一,但它并不必如此。

当存在 ByRef 参数时,调用方可能需要取回这些参数。 因此,如果 BindToMethod 已经操作参数数组,Binder 会允许客户端将参数数组映射回它的初始形式。 为了实现这一目的,必须向调用方保证参数的顺序不会改变。 当按名称传递参数时,Binder 将重新排列参数数组,这就是调用方所见的参数。 有关更多信息,请参见 Binder.ReorderArgumentArray

可用成员集包括在类型和任何基类型中定义的成员。 如果指定 BindingFlags.NonPublic,将返回该成员集中具有任何可访问性的成员。 如果未指定 BindingFlags.NonPublic,联编程序就必须强制可访问性规则。 当指定 PublicNonPublic 绑定标志时,还必须指定 InstanceStatic 绑定标志,否则不会返回任何成员。

如果只有一个成员具有给定名称,则不必进行回调,而在该方法上进行绑定。 代码示例的第 1 种情况说明了这一点:只有一个 PrintBob 方法可用,因此不需要进行回调。

如果可用集中有多个成员,所有这些方法都将传递给 BindToMethod,它将选择正确的方法并将其返回。 在代码示例的第 2 种情况下,有两个名为 PrintValue 的方法。 对 BindToMethod 的调用将选择正确的方法。

ChangeType 执行参数强制转换(类型转换),以便将实参转换为选定方法的形参的类型。 即使类型完全匹配,也会为每个参数调用 ChangeType

在代码示例的第 3 种情况下,将类型为 String 值为“5.5”的实参传递给了具有类型为 Double 的形参的方法。 要使调用成功,必须将字符串值“5.5”转换为 double 值。 ChangeType 会执行此转换。

ChangeType 仅执行无损或扩大强制,如下表所示。

源类型

目标类型

任何类型

它的基类型

任何类型

它所实现的接口

Char

UInt16、UInt32、Int32、UInt64、Int64、Single、Double

Byte

Char、UInt16、Int16、UInt32、Int32、UInt64、Int64、Single、Double

SByte

Int16、Int32、Int64、Single、Double

UInt16

UInt32、Int32、UInt64、Int64、Single、Double

Int16

Int32、Int64、Single、Double

UInt32

UInt64、Int64、Single、Double

Int32

Int64、Single、Double

UInt64

Single、Double

Int64

Single、Double

Single

Double

非引用类型

引用类型

Type 类具有 Get 方法,这些方法使用 Binder 类型的参数来解析对特定成员的引用。 Type.GetConstructorType.GetMethodType.GetProperty 通过提供当前类型的特定成员的签名信息来搜索该成员。 对 Binder.SelectMethodBinder.SelectProperty 进行回调以选择适当方法的给定签名信息。

请参见

参考

Type.InvokeMember

Assembly.Load

概念

查看类型信息

.NET Framework 中的类型转换