orlac
orlac
CC#
Created by orlac on 7/11/2024 in #help
Pattern matching `Type` in a way that can be assigned to a `const` variable... is it possible?
I'd like to come up with something where i can just have a lookup for a bunch of GUIDs that are assigned for each type. I write this, but it won't compile (I end up with error: CS8121 - but MS docs don't have any specifics about it for some reason). I had it implemented by taking in an object, which worked ok (it compiled at least), but I need to be able to do this lookup and assignment before any objects exist since it needs to be assigned to a const member variable. Any help/workarounds would be appreciated... it doesn't need to be structured exactly like this for the input or patterns in the switch, i'm just not too sure what other options I have when it comes to assigning the result to a const variable:
internal static class Constants {
public static string GUID(Type type) {
return type switch {
TypeA => "DEADBEEF-FEEE-FEEE-CDCD-000000000000",
TypeB => "DEADBEEF-FEEE-FEEE-CDCD-000000000001",
TypeC => "DEADBEEF-FEEE-FEEE-CDCD-000000000002",
TypeEtc => "DEADBEEF-FEEE-FEEE-CDCD-000000000004",

null => throw new ArgumentNullException(
$"GUID lookup failed, {nameof(type)} is null"
),
_ => throw new ArgumentException(
$"GUID lookup failed, type {type.Name} missing from GUID map"
),
};
}
}
internal static class Constants {
public static string GUID(Type type) {
return type switch {
TypeA => "DEADBEEF-FEEE-FEEE-CDCD-000000000000",
TypeB => "DEADBEEF-FEEE-FEEE-CDCD-000000000001",
TypeC => "DEADBEEF-FEEE-FEEE-CDCD-000000000002",
TypeEtc => "DEADBEEF-FEEE-FEEE-CDCD-000000000004",

null => throw new ArgumentNullException(
$"GUID lookup failed, {nameof(type)} is null"
),
_ => throw new ArgumentException(
$"GUID lookup failed, type {type.Name} missing from GUID map"
),
};
}
}
The assignment was planned to be something like this:
private const string GUID = Constants.GUID(TypeA);
private const string GUID = Constants.GUID(TypeA);
It's probably also worth mentioning this is for a VS2022 extension just to keep all of the extension component GUIDs defined in one place, so if there are alternatives to doing something like this (like some Visual Studio specific resource/config specific utilities I haven't found yet or something like that) i'd be happy to hear any suggestions anyone might have for this type of thing.
50 replies
CC#
Created by orlac on 6/28/2024 in #help
XmlReader skipping every other node while iterating
I have this code to parse a simple xml file:
private async IAsyncEnumerable<Compound> ParseCppReferenceIndexTags() {
string indexFilePath = Path.Join(
this.DocsRootDir.AbsolutePath,
@"cppreference-doxygen-local.tag.xml"
);

FileStream stream = new(indexFilePath, FileMode.Open);
await foreach (XElement elem in StreamElementsAsync(stream, "compound")) {
Compound compoundTag = new() {
Name = elem.Element("name")?.Value,
Type = elem.Attribute("kind")?.Value,
FileName = elem.Element("filename")?.Value,
NameSpace = elem.Attribute("kind")?.Value == "file"
? elem.Element("namespace")?.Value
: null
};

// other stuff..
yield return compoundTag;
}
}

private static async IAsyncEnumerable<XElement> StreamElementsAsync(Stream stream, string matchName) {
XmlReaderSettings settings = new() {
Async = true,
IgnoreWhitespace = true
};

using XmlReader reader = XmlReader.Create(stream, settings);
while (await reader.ReadAsync()) {
while (reader.ReadToFollowing(matchName))
if (await XNode.ReadFromAsync(reader, CancellationToken.None) is XElement elem)
yield return elem;
}
}
private async IAsyncEnumerable<Compound> ParseCppReferenceIndexTags() {
string indexFilePath = Path.Join(
this.DocsRootDir.AbsolutePath,
@"cppreference-doxygen-local.tag.xml"
);

FileStream stream = new(indexFilePath, FileMode.Open);
await foreach (XElement elem in StreamElementsAsync(stream, "compound")) {
Compound compoundTag = new() {
Name = elem.Element("name")?.Value,
Type = elem.Attribute("kind")?.Value,
FileName = elem.Element("filename")?.Value,
NameSpace = elem.Attribute("kind")?.Value == "file"
? elem.Element("namespace")?.Value
: null
};

// other stuff..
yield return compoundTag;
}
}

private static async IAsyncEnumerable<XElement> StreamElementsAsync(Stream stream, string matchName) {
XmlReaderSettings settings = new() {
Async = true,
IgnoreWhitespace = true
};

using XmlReader reader = XmlReader.Create(stream, settings);
while (await reader.ReadAsync()) {
while (reader.ReadToFollowing(matchName))
if (await XNode.ReadFromAsync(reader, CancellationToken.None) is XElement elem)
yield return elem;
}
}
The XML file looks like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<tagfile>
<compound kind="file">
<name>algorithm</name>
<filename>cpp/header/algorithm</filename>
<namespace>std</namespace>
</compound>
<compound kind="file">
<name>any</name>
<filename>cpp/header/any</filename>
<namespace>std</namespace>
</compound>
<compound kind="file">
<name>array</name>
<filename>cpp/header/array</filename>
<namespace>std</namespace>
</compound>
<compound kind="file">
<name>atomic</name>
<filename>cpp/header/atomic</filename>
<namespace>std</namespace>
</compound>
<compound kind="file">
<name>bit</name>
<filename>cpp/header/bit</filename>
<namespace>std</namespace>
</compound>
...
</tagfile>
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<tagfile>
<compound kind="file">
<name>algorithm</name>
<filename>cpp/header/algorithm</filename>
<namespace>std</namespace>
</compound>
<compound kind="file">
<name>any</name>
<filename>cpp/header/any</filename>
<namespace>std</namespace>
</compound>
<compound kind="file">
<name>array</name>
<filename>cpp/header/array</filename>
<namespace>std</namespace>
</compound>
<compound kind="file">
<name>atomic</name>
<filename>cpp/header/atomic</filename>
<namespace>std</namespace>
</compound>
<compound kind="file">
<name>bit</name>
<filename>cpp/header/bit</filename>
<namespace>std</namespace>
</compound>
...
</tagfile>
the data eventually makes its way into a sqlite db, but for some reason, when it's iterating through the top level component nodes, it seems to be skipping every other node because of some bad logic in StreamElementsAsync(). Is there something I should be using other than reader.ReadToFollowing(matchName) in the while loop to traverse all of the top level nodes? If that seems correct, does anyone happen to see anything else that might be off in the logic somewhere?
2 replies
CC#
Created by orlac on 6/27/2024 in #help
Parsing XML directly into serializable object?
I wrote a snippet of code to handle parsing an XML document into an IAsyncEnumerable of objects containing all of the necessary xml attributes/element data I want to capture, but was reading a bit about some better techniques for this type of thing and noticed some stackoverflow posts mentioning a method that's possible by using a type that's tagged with Serializable. The only issue is that I can't seem to find examples of how to do this. Is there an simple modification to this code here to be able to deserialize an XElement directly into a Compound object? The code is already starting to get messy and am hoping there's something I can use to either infer the schema of the XML document, then use that to serialize... or if possible just serialize into the object directly. This is the code I'd like to simplify with this type of an approach if possible: https://github.com/vorlac/cppreference-docs-vs-extension/blob/main/DocumentationProcessor/Core/Indexer.cs#L51-L145 And this is the XML doc being parsed: https://gist.github.com/vorlac/0514ed1920eb69d00e00af7631c1a528 Any help with the syntax needed to handle that conversion would be appreciated (or alternative parsing approaches altogether). The plan is to parse out as much info as possible, then store the data in a sqlite database, so if there are any shortcuts to pull that off (i.e. something that would allow a direct XML => sqlite transform).
1 replies