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
- Visual Studio 2022 version 17.3 eller senare med arbetsbelastningen .NET Desktop Development installerad. .NET 7 SDK ingår när du väljer den här arbetsbelastningen.
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.Sample
den 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 ReadOnlyFile
och 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;
}
- Lägg till följande
GetPropertyValue
-metod i klassenReadOnlyFile
. MetodenGetPropertyValue
tar, som indata, sökvillkor och returnerar raderna från en textfil som matchar sökvillkoren. De dynamiska metoder som tillhandahålls avReadOnlyFile
klassen anroparGetPropertyValue
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.