Exportieren (0) Drucken
Alle erweitern
Dieser Artikel wurde maschinell übersetzt. Bewegen Sie den Mauszeiger über die Sätze im Artikel, um den Originaltext anzuzeigen. Weitere Informationen
Übersetzung
Original

Dynamisches Laden und Verwenden von Typen

Reflektion stellt die Infrastruktur zur Verfügung, die Sprachcompiler wie Microsoft Visual Basic 2005 oder JScript verwenden, um implizite späte Bindung zu implementieren. Bindung besteht im Auffinden der Deklaration (d. h. der Implementierung), die sich auf einen eindeutig festgelegten Typ bezieht. Wenn dieser Prozess nicht während der Kompilierungszeit, sondern während der Laufzeit stattfindet, wird er als späte Bindung bezeichnet. Visual Basic 2005 lässt die Verwendung der impliziten späten Bindung im Code zu. Der Visual Basic-Compiler ruft eine Hilfsmethode auf, die unter Verwendung von Reflektion den Objekttyp abruft. Die an die Hilfsmethode übergebenen Argumente sorgen dafür, dass die richtige Methode zur Laufzeit aufgerufen wird. Es handelt sich um folgende Argumente: die Instanz (ein Objekt), für das die Methode aufgerufen werden soll, der Name der aufgerufenen Methode (eine Zeichenfolge) sowie die Argumente, die der aufgerufenen Methode übergeben werden (ein Objektarray).

Im folgenden Beispiel verwendet der Visual Basic-Compiler Reflektion, um implizit eine Methode für ein Objekt aufzurufen, dessen Typ zum Zeitpunkt der Kompilierung nicht bekannt ist. Eine HelloWorld-Klasse enthält eine PrintHello-Methode, die "Hello World" zusammen mit anderem, an sie übergebenen Text ausgibt. Die in diesem Beispiel aufgerufene PrintHello-Methode ist eigentlich ein Type.InvokeMember; im Visual Basic-Code kann die PrintHello-Methode so aufgerufen werden, als wäre der Objekttyp bereits zur Kompilierungszeit (frühes Binden) und nicht erst zur Laufzeit (spätes Binden) bekannt.

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

Reflektion kann nicht nur von Compilern implizit für spätes Binden eingesetzt werden, sondern auch explizit im Code.

Common Language Runtime unterstützt mehrere Programmiersprachen; die Bindungsregeln dieser Sprachen unterscheiden sich voneinander. Im Fall früher Bindung können Code-Generatoren den Bindungsvorgang vollständig kontrollieren. Im Fall später Bindung durch Reflektion muss der Vorgang durch benutzerdefinierte Bindung gesteuert werden. Die Binder-Klasse ermöglicht die benutzerdefinierte Steuerung für die Auswahl und den Aufruf von Membern.

Mit benutzerdefinierter Bindung können Sie eine Assembly zur Laufzeit laden, Informationen über Typen in dieser Assembly erhalten, den gewünschten Typ festlegen und anschließend für diesen Typ Methoden aufrufen oder auf Felder und Eigenschaften zugreifen. Diese Technik ist besonders nützlich, wenn ein Objekttyp zur Kompilierungszeit nicht bekannt ist, z. B. weil der Typ von Benutzereingaben abhängt.

Das folgende Beispiel veranschaulicht einen einfachen benutzerdefinierten Binder, der keine Argumenttypkonvertierung durchführt. Dem Hauptbeispiel geht Code für Simple_Type.dll voran. Stellen Sie sicher, dass Sie Simple_Type.dll erstellen und dann in das Projekt zur Erstellungszeit einen Verweis darauf aufnehmen.


// 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;
        }
    }
}


k3a58006.collapse_all(de-de,VS.110).gifInvokeMember und CreateInstance

Verwenden Sie Type.InvokeMember, um einen Member eines Typs aufzurufen. Die CreateInstance-Methoden verschiedener Klassen, z. B. System.Activator und System.Reflection.Assembly, sind spezielle Formen von InvokeMember, die neue Instanzen des angegebenen Typs erzeugen. Die Binder-Klasse wird für Überladungsauflösung und Argument-Coertion in diesen Methoden verwendet.

Im folgenden Beispiel werden die drei möglichen Kombinationen von Argument-Coertion (Typkonvertierung) und Memberauswahl dargestellt. Fall 1: Argument-Coertion oder Memberauswahl wird nicht benötigt. Fall 2: Nur Memberauswahl wird benötigt. Fall 3: Nur Argument-Coertion wird benötigt.


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


Überladungsauflösung wird dann benötigt, wenn mehrere Member gleichen Namens zur Verfügung stehen. Die Binder.BindToMethod-Methode und die Binder.BindToField-Methode werden verwendet, um Bindungen an einen einzelnen Member aufzulösen. Mit Binder.BindToMethod können Eigenschaften durch die Eigenschaften-Accessoren get und set aufgelöst werden.

BindToMethod gibt den aufzurufenden MethodBase zurück. Ist ein solcher Aufruf nicht möglich, wird ein NULL-Verweis (in Visual Basic Nothing) zurückgegeben. Der Rückgabewert von MethodBase ist nicht unbedingt im match-Parameter enthalten, obwohl dies der Normalfall ist.

Sind ByRef-Argumente vorhanden, könnte der Aufrufer die Argumente zurückverlangen. Aus diesem Grund erlaubt Binder einem Client, das Argumentarray seinem ursprünglichen Zustand zuzuordnen, falls das Array durch BindToMethod verändert wurde. Zu diesem Zweck muss dem Aufrufer gewährleistet werden, dass die Reihenfolge der Argumente unverändert bleibt. Wenn Argumente nach Namen übergeben werden, erstellt Binder eine neue Anordnung des Argumentarrays. Nur dieses ist für den Aufrufer sichtbar. Weitere Informationen finden Sie unter Binder.ReorderArgumentArray.

Die Menge verfügbarer Member besteht aus den im Typ oder einem beliebigen Basistyp definierten Membern. Ist BindingFlags.NonPublic angegeben, werden Member unabhängig von ihrer Zugänglichkeit an die Menge zurückgegeben. Andernfalls muss der Binder Zugänglichkeitsregeln erzwingen. Wenn die Bindungsflags Public oder NonPublic gesetzt sind, müssen auch die Bindungsflags Instance oder Static gesetzt werden, sonst wird kein Member zurückgegeben.

Gibt es nur einen Member des jeweiligen Namens, ist kein Rückruf erforderlich, und die Bindung wird für diese Methode vorgenommen. Im 1. Fall des Codebeispiels gibt es nur eine verfügbare PrintBob-Methode, daher ist kein Rückruf erforderlich.

Gibt es mehrere Member in der verfügbaren Menge, werden alle diese Methoden an BindToMethod übergeben, wodurch die richtige Methode ausgewählt und zurückgegeben wird. Im 2. Fall des Codebeispiels gibt es zwei Methoden namens PrintValue. Die richtige Methode wird durch einen Aufruf von BindToMethod ausgewählt.

ChangeType führt Argument-Coertion (Typkonvertierung) durch, wobei die tatsächlichen Argumente in den Typ der formalen Argumente der ausgewählten Methode konvertiert werden. ChangeType wird für jedes Argument aufgerufen, selbst dann, wenn die Typen exakt übereinstimmen.

Im 3. Fall des Codebeispiels wird ein Argument des Typs String mit dem Wert "5,5" an eine Methode mit einem formalen Argument vom Typ Double übergeben. Für einen erfolgreichen Aufruf muss der Zeichenfolgenwert "5,5" in einen Double-Wert konvertiert werden. Die Konvertierung wird von ChangeType übernommen.

ChangeType führt nur verlustfreie oder erweiternde Coertionen aus, wie in folgender Tabelle beschrieben:

Quelltyp

Zieltyp

Beliebiger Typ

Der entsprechende Basistyp.

Beliebiger Typ

Implementierte Schnittstelle

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

Kein Referenztyp

Verweistyp

Die Type-Klasse enthält Get-Methoden, die mithilfe von Parametern vom Typ Binder Verweise auf einen bestimmten Member auflösen. Type.GetConstructor , Type.GetMethod und Type.GetProperty suchen nach einem bestimmten Member des aktuellen Typs, indem sie die Signaturinformationen für diesen Member zur Verfügung stellen. Binder.SelectMethod und Binder.SelectProperty werden zur Auswahl der jeweiligen Signaturinformationen der entsprechenden Methoden aufgerufen.

Community-Beiträge

HINZUFÜGEN
Anzeigen:
© 2015 Microsoft