Návod: Vytváření a používání dynamických objektů v jazyce C#

Dynamické objekty zpřístupňují členy, jako jsou vlastnosti a metody za běhu, a ne v době kompilace. Dynamické objekty umožňují vytvářet objekty pro práci se strukturami, které neodpovídají statickému typu nebo formátu. Pomocí dynamického objektu můžete například odkazovat na model DOM (Document Object Model) HTML, který může obsahovat libovolnou kombinaci platných elementů a atributů značek HTML. Vzhledem k tomu, že každý dokument HTML je jedinečný, členové určitého dokumentu HTML jsou určeny za běhu. Běžnou metodou odkazování na atribut elementu HTML je předat název atributu GetProperty metodě elementu. Chcete-li odkazovat na id atribut html element <div id="Div1">, nejprve získáte odkaz na <div> element a pak použít divElement.GetProperty("id"). Pokud používáte dynamický objekt, můžete odkazovat na id atribut jako divElement.id.

Dynamické objekty také poskytují pohodlný přístup k dynamickým jazykům, jako je IronPython a IronRuby. Dynamický objekt můžete použít k odkazování na dynamický skript interpretovaný za běhu.

Na dynamický objekt odkazujete pomocí pozdní vazby. Typ pozdního vázaného objektu zadáte jako dynamic. Další informace najdete v dynamickém zobrazení.

Vlastní dynamické objekty můžete vytvořit pomocí tříd v System.Dynamic oboru názvů. Můžete například vytvořit ExpandoObject a zadat členy tohoto objektu za běhu. Můžete také vytvořit vlastní typ, který dědí DynamicObject třídu. Potom můžete přepsat členy DynamicObject třídy, aby poskytovaly dynamické funkce za běhu.

Tento článek obsahuje dva nezávislé názorné postupy:

  • Vytvořte vlastní objekt, který dynamicky zveřejňuje obsah textového souboru jako vlastnosti objektu.
  • Vytvořte projekt, který používá knihovnu IronPython .

Požadavky

Poznámka:

Váš počítač může v následujících pokynech zobrazovat odlišné názvy nebo umístění některých prvků uživatelského rozhraní sady Visual Studio. Tyto prvky jsou určeny edicí sady Visual Studio a použitým nastavením. Další informace najdete v tématu Přizpůsobení integrovaného vývojového prostředí.

  • Pro druhý názorný postup nainstalujte IronPython pro .NET. Přejděte na stránku Pro stažení a získejte nejnovější verzi.

Vytvoření vlastního dynamického objektu

První návod definuje vlastní dynamický objekt, který prohledá obsah textového souboru. Dynamická vlastnost určuje hledaný text. Pokud například volání kódu určuje dynamicFile.Sample, dynamická třída vrátí obecný seznam řetězců, které obsahují všechny řádky ze souboru, které začínají na "Sample". Hledání nerozlišuje malá a velká písmena. Dynamická třída podporuje také dva volitelné argumenty. Prvním argumentem je hodnota výčtu možností hledání, která určuje, že dynamická třída by měla hledat shody na začátku řádku, na konci řádku nebo kdekoli na řádku. Druhý argument určuje, že dynamická třída by měla před hledáním oříznout úvodní a koncové mezery z každého řádku. Pokud například volání kódu určuje dynamicFile.Sample(StringSearchOption.Contains), dynamická třída vyhledá "Sample" kdekoli na řádku. Pokud volání kódu určuje dynamicFile.Sample(StringSearchOption.StartsWith, false), dynamická třída hledá na začátku každého řádku "Sample" a neodebere úvodní a koncové mezery. Výchozím chováním dynamické třídy je vyhledání shody na začátku každého řádku a odebrání úvodních a koncových mezer.

Vytvoření vlastní dynamické třídy

Spusťte Visual Studio. Vyberte Vytvořit nový projekt. V dialogovém okně Vytvořit nový projekt vyberte C#, vyberte Konzolová aplikace a pak vyberte Další. V dialogovém okně Konfigurovat nový projekt zadejte DynamicSample název projektu a pak vyberte Další. V dialogovém okně Další informace vyberte .NET 7.0 (Aktuální) pro cílovou architekturu a pak vyberte Vytvořit. V Průzkumník řešení klikněte pravým tlačítkem na projekt DynamicSample a vyberte Přidat>třídu. Do pole Název zadejte ReadOnlyFilea pak vyberte Přidat. V horní části souboru ReadOnlyFile.cs nebo ReadOnlyFile.vb přidejte následující kód pro import objektů System.IO a System.Dynamic oborů názvů.

using System.IO;
using System.Dynamic;

Vlastní dynamický objekt používá výčt k určení kritérií hledání. Před příkaz třídy přidejte následující definici výčtu.

public enum StringSearchOption
{
    StartsWith,
    Contains,
    EndsWith
}

Aktualizujte příkaz třídy tak, aby dědil DynamicObject třídu, jak je znázorněno v následujícím příkladu kódu.

class ReadOnlyFile : DynamicObject

Do třídy přidejte následující kód ReadOnlyFile , který definuje privátní pole pro cestu k souboru a konstruktor pro ReadOnlyFile třídu.

// 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. Do třídy ReadOnlyFile přidejte následující metodu GetPropertyValue. Metoda GetPropertyValue přebírá jako vstupní kritéria kritéria hledání a vrací řádky z textového souboru, který odpovídá hledanému kritériu. Dynamické metody poskytované ReadOnlyFile třídou volají metodu GetPropertyValue pro načtení příslušných výsledků.
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;
}

Za metodu GetPropertyValue přidejte následující kód, který přepíše TryGetMember metodu DynamicObject třídy. Metoda TryGetMember je volána, když je požadován člen dynamické třídy a nejsou zadány žádné argumenty. Argument binder obsahuje informace o odkazovaném členu a result argument odkazuje na výsledek vrácený pro zadaný člen. Metoda TryGetMember vrátí logickou hodnotu, která vrátí true , pokud požadovaný člen existuje; jinak vrátí 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;
}

Za metodu TryGetMember přidejte následující kód, který přepíše TryInvokeMember metodu DynamicObject třídy. Metoda TryInvokeMember je volána, když člen dynamické třídy je požadován s argumenty. Argument binder obsahuje informace o odkazovaném členu a result argument odkazuje na výsledek vrácený pro zadaný člen. Argument args obsahuje pole argumentů, které jsou předány členu. Metoda TryInvokeMember vrátí logickou hodnotu, která vrátí true , pokud požadovaný člen existuje; jinak vrátí false.

Vlastní verze TryInvokeMember metody očekává, že první argument bude hodnotou z výčtu StringSearchOption , který jste definovali v předchozím kroku. Metoda TryInvokeMember očekává, že druhým argumentem bude logická hodnota. Pokud jsou jeden nebo oba argumenty platné hodnoty, předají GetPropertyValue se metodě pro načtení výsledků.

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

Soubor uložte a zavřete.

Vytvoření ukázkového textového souboru

V Průzkumník řešení klikněte pravým tlačítkem myši na projekt DynamicSample a vyberte Přidat>novou položku. V podokně Nainstalované šablony vyberte Obecné a pak vyberte šablonu Textové soubory. V poli Název ponechte výchozí název TextFile1.txta pak vyberte Přidat. Zkopírujte následující text do souboru 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

Soubor uložte a zavřete.

Vytvoření ukázkové aplikace, která používá vlastní dynamický objekt

V Průzkumník řešení poklikejte na soubor Program.cs. Do procedury přidejte následující kód Main , který vytvoří instanci ReadOnlyFile třídy pro TextFile1.txt soubor. Kód používá pozdní vazbu k volání dynamických členů a načtení řádků textu, které obsahují řetězec "Customer".

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

Uložte soubor a stisknutím ctrl +F5 sestavte a spusťte aplikaci.

Volání dynamické jazykové knihovny

Následující názorný postup vytvoří projekt, který přistupuje k knihovně napsané v dynamickém jazyce IronPython.

Vytvoření vlastní dynamické třídy

V sadě Visual Studio vyberte Soubor>nový>projekt. V dialogovém okně Vytvořit nový projekt vyberte C#, vyberte Konzolová aplikace a pak vyberte Další. V dialogovém okně Konfigurovat nový projekt zadejte DynamicIronPythonSample název projektu a pak vyberte Další. V dialogovém okně Další informace vyberte .NET 7.0 (Aktuální) pro cílovou architekturu a pak vyberte Vytvořit. Nainstalujte balíček NuGet IronPython. Upravte soubor Program.cs. V horní části souboru přidejte následující kód pro import a Microsoft.Scripting.HostingIronPython.Hosting obory názvů z knihoven IronPython a System.Linq oboru názvů.

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

Do metody Main přidejte následující kód pro vytvoření nového Microsoft.Scripting.Hosting.ScriptRuntime objektu pro hostování knihoven IronPython. Objekt ScriptRuntime načte modul knihovny IronPython 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.");

Po načtení kódu modulu random.py přidejte následující kód, který vytvoří pole celých čísel. Pole se předává shuffle metodě modulu random.py, který náhodně seřadí hodnoty v matici.

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

Uložte soubor a stisknutím ctrl +F5 sestavte a spusťte aplikaci.

Viz také