Aracılığıyla paylaş


Türleri dinamik olarak yükleme ve kullanma

Yansıma, dil derleyicileri tarafından örtük geç bağlama uygulamak için kullanılan altyapıyı sağlar. Bağlama, benzersiz olarak belirtilen bir türe karşılık gelen bildirimi (uygulama) bulma işlemidir. Bu işlem derleme zamanında değil çalışma zamanında gerçekleştiğinde, geç bağlama olarak adlandırılır. Visual Basic, kodunuzda örtük geç bağlama kullanmanıza olanak tanır; Visual Basic derleyicisi, nesne türünü almak için yansıma kullanan bir yardımcı yöntemi çağırır. Yardımcı metoda geçirilen bağımsız değişkenler, uygun metodun çalışma zamanı sırasında çağrılmasını sağlar. Bu bağımsız değişkenler, yönteminin çağrıldığı örnek (nesne), çağrılan yöntemin adı (dize) ve çağrılan yönteme geçirilen bağımsız değişkenlerdir (bir nesne dizisi).

Aşağıdaki örnekte Visual Basic derleyicisi, derleme zamanında türü bilinmeyen bir nesnedeki bir yöntemi çağırmak için örtük olarak yansıma kullanır. Bir HelloWorld sınıfında, kendisine geçirilen bir metinle birleştirilmiş "Hello World" yazdıran bir PrintHelloPrintHello yöntemi vardır. PrintHello Bu örnekte çağrılan yöntem aslında bir Type.InvokeMember yöntemidir; Visual Basic kodu, nesnenin helloObj türü çalışma zamanında (geç bağlama) değil, derleme zamanında (erken bağlama) biliniyormuş gibi PrintHello yönteminin çağrılmasını sağlar.

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

Özel bağlama

Geç bağlama için derleyiciler tarafından örtük olarak kullanılmaya ek olarak, yansıma, geç bağlamayı gerçekleştirmek için kodda açıkça kullanılabilir.

Ortak dil çalışma zamanı birden çok programlama dilini destekler ve bu dillerin bağlama kuralları farklıdır. Erken bağlama durumunda, kod oluşturucular bu bağlamayı tamamen denetleyebilir. Ancak, yansıtma mekanizması aracılığıyla geç dinamik bağlamada, bağlama özelleştirilmiş bağlama mekanizması tarafından denetlenmelidir. sınıfı, Binder üye seçimi ve çağırma için özel denetim sağlar.

Özel bağlamayı kullanarak bir derlemeyi çalışma zamanında yükleyebilir, bu derlemedeki türler hakkında bilgi alabilir, istediğiniz türü belirtebilir ve ardından bu türdeki yöntemleri çağırabilir veya alanlara veya özelliklere erişebilirsiniz. Bu teknik, derleme zamanında nesne türünün kullanıcı girişlerine bağımlı olması gibi bir nesnenin türünü bilmiyorsanız kullanışlıdır.

Aşağıdaki örnekte bağımsız değişken türü dönüştürmesi sağlamayan basit bir özel bağlayıcı gösterilmektedir. için Simple_Type.dll kod, ana örnekten önce yer alır. Simple_Type.dll kaynak kodunu oluşturduğunuzdan ve ardından derleme zamanında projeye bir referans eklediğinizden emin olun.

// 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 ve CreateInstance

Bir türün üyesini çağırmak için kullanın Type.InvokeMember . CreateInstance ve Activator.CreateInstancegibi Assembly.CreateInstance çeşitli sınıfların yöntemleri, belirtilen türün InvokeMember yeni örneklerini oluşturan özel biçimlerdir. sınıfı Binder , bu yöntemlerde aşırı yükleme çözümlemesi ve bağımsız değişken zorlaması için kullanılır.

Aşağıdaki örnek, bağımsız değişken zorlaması (tür dönüştürme) ve üye seçiminin üç olası kombinasyonunu göstermektedir. Durum 1'de, argüman dökümü veya üye seçimi gerekmez. 2. Durumda, yalnızca üye seçimi gereklidir. Durum 3'te, yalnızca bağımsız değişken zorlaması gereklidir.

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

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

    public static void PrintNumber(double value)
    {
        Console.WriteLine($"PrintNumber ({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

Aynı ada sahip birden fazla üye mevcut olduğunda, aşırı yükleme çözümü gereklidir. Binder.BindToMethod ve Binder.BindToField yöntemleri, tek bir üyeye bağlamayı çözümlemek için kullanılır. Binder.BindToMethod ayrıca get ve set özellik erişimcileri aracılığıyla özellik çözümlemesi sağlar.

BindToMethod, çağırılacak MethodBase değerini ya da böyle bir çağrı mümkün değilse bir null başvuruyu (Nothing Visual Basic'te) döndürür. Dönüş MethodBase değeri, her zamanki durum bu olsa da, match parametresinde yer alan değerlerden biri olmak zorunda değildir.

ByRef bağımsız değişkenleri mevcut olduğunda, çağıran bunları geri almak isteyebilir. Bu nedenle, Binder bir istemcinin bağımsız değişken dizisini değiştirdiyse BindToMethod , bağımsız değişken dizisini özgün biçimine geri eşlemesine izin verir. Bunu yapmak için, çağırana bağımsız değişkenlerin sırasının değişmediği garanti edilmelidir. Bağımsız değişkenler adlarına göre geçirildiğinde, Binder bağımsız değişken dizisini yeniden sıralar ve bu, çağıranın gördüğü sonuçtur. Daha fazla bilgi için bkz. Binder.ReorderArgumentArray.

Kullanılabilir üyeler kümesi, ilgili türde veya herhangi bir temel türde tanımlanmış üyelerdir. Eğer BindingFlags belirtilirse, herhangi bir erişilebilirlik seviyesinin üyeleri kümede döndürülür. Belirtilmediği takdirde BindingFlags.NonPublic, bağlayıcı erişilebilirlik kurallarını uygulamak zorundadır. Public veya NonPublic bağlama bayrağını belirtirken, Instance veya Static bağlama bayrağını da belirtmelisiniz, aksi takdirde hiçbir üye döndürülmeyecektir.

Verilen adın yalnızca bir üyesi varsa, geri çağırma gerekmez ve bu yöntemde bağlama yapılır. Kod örneğinin 1. durumu şu noktayı gösterir: Yalnızca bir PrintBob yöntem kullanılabilir ve bu nedenle geri çağırma gerekmez.

Kullanılabilir kümede birden fazla üye varsa, tüm bu yöntemler uygun yöntemi seçip döndüren öğesine BindToMethodgeçirilir. Kod örneğinin 2. durumunda adlı PrintValueiki yöntem vardır. Uygun olan yöntem, BindToMethod tarafından seçilir.

ChangeType gerçek bağımsız değişkenleri seçilen yöntemin resmi bağımsız değişkenlerinin türüne dönüştüren bağımsız değişken zorlaması (tür dönüştürme) gerçekleştirir. Türler tam olarak eşleşse bile, her argüman için ChangeType çağrılır.

Kod örneğinin 3. durumunda, "5,5" değerine sahip String türündeki gerçek bir bağımsız değişken Double türünde resmi bir bağımsız değişkeni olan bir yönteme geçirilir. Çağırmanın başarılı olması için "5,5" dize değerinin çift değere dönüştürülmesi gerekir. ChangeType bu dönüştürmeyi gerçekleştirir.

ChangeType aşağıdaki tabloda gösterildiği gibi yalnızca kayıpsız veya genişleyen zorlamalar gerçekleştirir.

Kaynak türü Hedef türü
Herhangi bir tür Temel türü
Herhangi bir tür Uyguladığı arabirim
Karakter UInt16, UInt32, Int32, UInt64, Int64, Tek (Single), Çift (Double)
Bayt Char, UInt16, Int16, UInt32, Int32, UInt64, Int64, Tek, Çift
SByte Int16, Int32, Int64, Tek, Çift
UInt16 UInt32, Int32, UInt64, Int64, Tek, Çift
Int16 Int32, Int64, Tek, Çift
UInt32 UInt64, Int64, Tek, Çift
Int32 Int64, Tek, Çift
UInt64 Tek, Çift
Int64 Tek, Çift
Tek İki kat
Başvuru olmayan tür Referans türü

Type sınıfı, türündeki Get parametreleri kullanan Binder yöntemlere, belirli bir üyeye yapılan başvuruları çözümlemek için sahiptir. Type.GetConstructor, Type.GetMethod ve Type.GetProperty, ilgili üyenin imza bilgilerini sağlayarak geçerli türün belirli bir üyesini arar. Binder.SelectMethod ve Binder.SelectProperty uygun yöntemlerin verilen imza bilgilerini seçmek için yeniden çağrılır.

Ayrıca bkz.