Dela via


Genomgång: Skapa och använda dynamiska objekt i C#

Dynamiska objekt exponerar medlemmar, till exempel egenskaper och metoder vid körning, i stället för vid kompileringstid. Med dynamiska objekt kan du skapa objekt som fungerar med strukturer som inte matchar en statisk typ eller ett statiskt format. Du kan till exempel använda ett dynamiskt objekt för att referera till HTML-dokumentobjektmodellen (DOM), som kan innehålla valfri kombination av giltiga HTML-markeringselement och attribut. Eftersom varje HTML-dokument är unikt bestäms medlemmarna för ett visst HTML-dokument vid körning. En vanlig metod för att referera till ett attribut för ett HTML-element är att skicka namnet på attributet till GetProperty -metoden för elementet. Om du vill referera id till attributet för HTML-elementet <div id="Div1">hämtar du först en referens till elementet <div> och använder divElement.GetProperty("id")sedan . Om du använder ett dynamiskt objekt kan du referera till id attributet som divElement.id.

Dynamiska objekt ger också bekväm åtkomst till dynamiska språk som IronPython och IronRuby. Du kan använda ett dynamiskt objekt för att referera till ett dynamiskt skript som tolkas vid körning.

Du refererar till ett dynamiskt objekt med hjälp av sen bindning. Du anger typen av ett sent bundet objekt som dynamic. Mer information finns i Dynamisk.

Du kan skapa anpassade dynamiska objekt med hjälp av klasserna i System.Dynamic namnområdet. Du kan till exempel skapa en ExpandoObject och ange medlemmarna i objektet vid körning. Du kan också skapa en egen typ som ärver DynamicObject klassen. Du kan sedan åsidosätta medlemmarna i DynamicObject klassen för att tillhandahålla dynamiska funktioner för körning.

Den här artikeln innehåller två oberoende genomgångar:

  • Skapa ett anpassat objekt som dynamiskt exponerar innehållet i en textfil som egenskaper för ett objekt.
  • Skapa ett projekt som använder ett IronPython bibliotek.

Förutsättningar

Kommentar

Datorn kan visa olika namn eller platser för vissa av Visual Studio-användargränssnittselementen i följande instruktioner. Den Visual Studio-utgåva som du har och de inställningar som du använder avgör dessa element. Mer information finns i Anpassa IDE.

  • För den andra genomgången installerar du IronPython för .NET. Gå till nedladdningssidan för att hämta den senaste versionen.

Skapa ett anpassat dynamiskt objekt

Den första genomgången definierar ett anpassat dynamiskt objekt som söker i innehållet i en textfil. En dynamisk egenskap anger den text som ska sökas efter. Om anropande kod till exempel anger returnerar dynamicFile.Sampleden dynamiska klassen en allmän lista med strängar som innehåller alla rader från filen som börjar med "Exempel". Sökningen är skiftlägeskänslig. Den dynamiska klassen stöder också två valfria argument. Det första argumentet är ett uppräkningsvärde för sökalternativ som anger att den dynamiska klassen ska söka efter matchningar i början av raden, slutet av raden eller var som helst på raden. Det andra argumentet anger att den dynamiska klassen ska trimma inledande och avslutande blanksteg från varje rad innan du söker. Om anropskoden dynamicFile.Sample(StringSearchOption.Contains)till exempel anger söker den dynamiska klassen efter "Sample" var som helst på en rad. Om anropskoden dynamicFile.Sample(StringSearchOption.StartsWith, false)anger söker den dynamiska klassen efter "Exempel" i början av varje rad och tar inte bort inledande och avslutande blanksteg. Standardbeteendet för den dynamiska klassen är att söka efter en matchning i början av varje rad och ta bort inledande och avslutande blanksteg.

Skapa en anpassad dynamisk klass

Starta Visual Studio. Välj Skapa ett nytt projekt. I dialogrutan Skapa ett nytt projekt väljer du C#, konsolprogram och sedan Nästa. I dialogrutan Konfigurera det nya projektet anger du DynamicSample som Projektnamn och väljer sedan Nästa. I dialogrutan Ytterligare information väljer du .NET 7.0 (aktuell) för Target Framework och väljer sedan Skapa. Högerklicka på Projektet DynamicSample i Solution Explorer och välj Lägg till>klass. I rutan Namn skriver du ReadOnlyFileoch väljer sedan Lägg till. Överst i filen ReadOnlyFile.cs eller ReadOnlyFile.vb lägger du till följande kod för att importera System.IO namnrymderna och System.Dynamic .

using System.IO;
using System.Dynamic;

Det anpassade dynamiska objektet använder en uppräkning för att fastställa sökvillkoren. Lägg till följande uppräkningsdefinition före klass-instruktionen.

public enum StringSearchOption
{
    StartsWith,
    Contains,
    EndsWith
}

Uppdatera klass-instruktionen DynamicObject för att ärva klassen, enligt följande kodexempel.

class ReadOnlyFile : DynamicObject

Lägg till följande kod i ReadOnlyFile klassen för att definiera ett privat fält för filsökvägen och en konstruktor för ReadOnlyFile klassen.

// Store the path to the file and the initial line count value.
private string p_filePath;

// Public constructor. Verify that file exists and store the path in
// the private variable.
public ReadOnlyFile(string filePath)
{
    if (!File.Exists(filePath))
    {
        throw new Exception("File path does not exist.");
    }

    p_filePath = filePath;
}
  1. Lägg till följande GetPropertyValue-metod i klassen ReadOnlyFile. Metoden GetPropertyValue tar, som indata, sökvillkor och returnerar raderna från en textfil som matchar sökvillkoren. De dynamiska metoder som tillhandahålls av ReadOnlyFile klassen anropar GetPropertyValue metoden för att hämta respektive resultat.
public List<string> GetPropertyValue(string propertyName,
                                     StringSearchOption StringSearchOption = StringSearchOption.StartsWith,
                                     bool trimSpaces = true)
{
    StreamReader sr = null;
    List<string> results = new List<string>();
    string line = "";
    string testLine = "";

    try
    {
        sr = new StreamReader(p_filePath);

        while (!sr.EndOfStream)
        {
            line = sr.ReadLine();

            // Perform a case-insensitive search by using the specified search options.
            testLine = line.ToUpper();
            if (trimSpaces) { testLine = testLine.Trim(); }

            switch (StringSearchOption)
            {
                case StringSearchOption.StartsWith:
                    if (testLine.StartsWith(propertyName.ToUpper())) { results.Add(line); }
                    break;
                case StringSearchOption.Contains:
                    if (testLine.Contains(propertyName.ToUpper())) { results.Add(line); }
                    break;
                case StringSearchOption.EndsWith:
                    if (testLine.EndsWith(propertyName.ToUpper())) { results.Add(line); }
                    break;
            }
        }
    }
    catch
    {
        // Trap any exception that occurs in reading the file and return null.
        results = null;
    }
    finally
    {
        if (sr != null) {sr.Close();}
    }

    return results;
}

GetPropertyValue Efter metoden lägger du till följande kod för att åsidosätta TryGetMember -metoden för DynamicObject klassen. Metoden TryGetMember anropas när en medlem i en dynamisk klass begärs och inga argument anges. Argumentet binder innehåller information om den refererade medlemmen och result argumentet refererar till resultatet som returneras för den angivna medlemmen. Metoden TryGetMember returnerar ett booleskt värde som returnerar true om den begärda medlemmen finns. Annars returneras false.

// Implement the TryGetMember method of the DynamicObject class for dynamic member calls.
public override bool TryGetMember(GetMemberBinder binder,
                                  out object result)
{
    result = GetPropertyValue(binder.Name);
    return result == null ? false : true;
}

TryGetMember Efter metoden lägger du till följande kod för att åsidosätta TryInvokeMember -metoden för DynamicObject klassen. Metoden TryInvokeMember anropas när en medlem i en dynamisk klass begärs med argument. Argumentet binder innehåller information om den refererade medlemmen och result argumentet refererar till resultatet som returneras för den angivna medlemmen. Argumentet args innehåller en matris med argumenten som skickas till medlemmen. Metoden TryInvokeMember returnerar ett booleskt värde som returnerar true om den begärda medlemmen finns. Annars returneras false.

Den anpassade versionen av TryInvokeMember metoden förväntar sig att det första argumentet är ett värde från den StringSearchOption uppräkning som du definierade i ett tidigare steg. Metoden TryInvokeMember förväntar sig att det andra argumentet är ett booleskt värde. Om ett eller båda argumenten är giltiga värden skickas de till GetPropertyValue metoden för att hämta resultatet.

// Implement the TryInvokeMember method of the DynamicObject class for
// dynamic member calls that have arguments.
public override bool TryInvokeMember(InvokeMemberBinder binder,
                                     object[] args,
                                     out object result)
{
    StringSearchOption StringSearchOption = StringSearchOption.StartsWith;
    bool trimSpaces = true;

    try
    {
        if (args.Length > 0) { StringSearchOption = (StringSearchOption)args[0]; }
    }
    catch
    {
        throw new ArgumentException("StringSearchOption argument must be a StringSearchOption enum value.");
    }

    try
    {
        if (args.Length > 1) { trimSpaces = (bool)args[1]; }
    }
    catch
    {
        throw new ArgumentException("trimSpaces argument must be a Boolean value.");
    }

    result = GetPropertyValue(binder.Name, StringSearchOption, trimSpaces);

    return result == null ? false : true;
}

Spara och stäng filen.

Skapa en exempeltextfil

Högerklicka på Projektet DynamicSample i Solution Explorer och välj Lägg till>nytt objekt. I fönstret Installerade mallar väljer du Allmänt och sedan mallen Textfil . Lämna standardnamnet för TextFile1.txt i rutan Namn och välj sedan Lägg till. Kopiera följande text till filen TextFile1.txt .

List of customers and suppliers

Supplier: Lucerne Publishing (https://www.lucernepublishing.com/)
Customer: Preston, Chris
Customer: Hines, Patrick
Customer: Cameron, Maria
Supplier: Graphic Design Institute (https://www.graphicdesigninstitute.com/)
Supplier: Fabrikam, Inc. (https://www.fabrikam.com/)
Customer: Seubert, Roxanne
Supplier: Proseware, Inc. (http://www.proseware.com/)
Customer: Adolphi, Stephan
Customer: Koch, Paul

Spara och stäng filen.

Skapa ett exempelprogram som använder det anpassade dynamiska objektet

Dubbelklicka på filen Program.cs i Solution Explorer. Lägg till följande kod i proceduren Main för att skapa en instans av ReadOnlyFile klassen för TextFile1.txt-filen. Koden använder sen bindning för att anropa dynamiska medlemmar och hämta textrader som innehåller strängen "Kund".

dynamic rFile = new ReadOnlyFile(@"..\..\..\TextFile1.txt");
foreach (string line in rFile.Customer)
{
    Console.WriteLine(line);
}
Console.WriteLine("----------------------------");
foreach (string line in rFile.Customer(StringSearchOption.Contains, true))
{
    Console.WriteLine(line);
}

Spara filen och tryck på Ctrl+F5 för att skapa och köra programmet.

Anropa ett dynamiskt språkbibliotek

Följande genomgång skapar ett projekt som kommer åt ett bibliotek skrivet på det dynamiska språket IronPython.

Skapa en anpassad dynamisk klass

Välj Arkiv>Nytt>Projekt i Visual Studio. I dialogrutan Skapa ett nytt projekt väljer du C#, konsolprogram och sedan Nästa. I dialogrutan Konfigurera det nya projektet anger du DynamicIronPythonSample som Projektnamn och väljer sedan Nästa. I dialogrutan Ytterligare information väljer du .NET 7.0 (aktuell) för Target Framework och väljer sedan Skapa. Installera NuGet-paketet IronPython. Redigera filen Program.cs . Överst i filen lägger du till följande kod för att importera Microsoft.Scripting.Hosting namnrymderna och IronPython.Hosting från IronPython-biblioteken System.Linq och namnområdet.

using System.Linq;
using Microsoft.Scripting.Hosting;
using IronPython.Hosting;

I main-metoden lägger du till följande kod för att skapa ett nytt Microsoft.Scripting.Hosting.ScriptRuntime objekt som ska vara värd för IronPython-biblioteken. Objektet ScriptRuntime läser in modulen IronPython-bibliotek random.py.

// Set the current directory to the IronPython libraries.
System.IO.Directory.SetCurrentDirectory(
   Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) +
   @"\IronPython 2.7\Lib");

// Create an instance of the random.py IronPython library.
Console.WriteLine("Loading random.py");
ScriptRuntime py = Python.CreateRuntime();
dynamic random = py.UseFile("random.py");
Console.WriteLine("random.py loaded.");

När koden för att läsa in modulen random.py lägger du till följande kod för att skapa en matris med heltal. Matrisen skickas till shuffle metoden för modulen random.py, som slumpmässigt sorterar värdena i matrisen.

// Initialize an enumerable set of integers.
int[] items = Enumerable.Range(1, 7).ToArray();

// Randomly shuffle the array of integers by using IronPython.
for (int i = 0; i < 5; i++)
{
    random.shuffle(items);
    foreach (int item in items)
    {
        Console.WriteLine(item);
    }
    Console.WriteLine("-------------------");
}

Spara filen och tryck på Ctrl+F5 för att skapa och köra programmet.

Se även