Seeking guidance reading .yaml files with C# - c#

Two months later:
The YAML (Eve Online blueprint.yaml) file I tried to parse changed a huge deal which also made it much easier to parse using de deserializer. If someone (for whatever reason) would like to see the code, it's updated on https://github.com/hkraal/ParseYaml
Based on the comment of Steve Wellens I've adjusted the code to do less things at once. It didn't matter in the error itself. I've created another project (Example1) in my solution to test the actual example found on aaubry.net I referenced to earlier.
It gave me the same error when using an "dynamic" key which lead to my current conclusion:
There is a difference between:
items:
- part_no: A4786
and
items:
part_no: A4786
The first is being used in the example which I (wrongly) assumed I could apply to my .yaml file which is using the second syntax.
Now it remains to find out how I can get the 'child' elements of my key with the syntax used in my yaml file...
As C# is used at work I started thinking about a nice project to learn about various aspects of the language while having a direct goal to work towards. However I'm hitting my first wall quite early in my project parsing a Yaml file. My goal is to create an List of YamlBlueprint objects as defined in YamlBlueprint.cs but I don't even get to the end of the Yaml file.
I've setup a testcase on github which demonstrates the problem:
https://github.com/hkraal/ParseYaml
The example on http://www.aaubry.net/page/YamlDotNet-Documentation-Loading-a-YAML-stream works up untill I want to loop trough the items. Based on what I see I should be able to give myKey as parameter to the YamlScalarNode() to access the items below it.
var items = (YamlSequenceNode)mapping.Children[new YamlScalarNode(myKey)];
I'm gettting the following error if I do:
An unhandled exception of type 'System.InvalidCastException' occurred in yamldotnet.exe
Additional information: Unable to cast object of type 'YamlDotNet.RepresentationModel.YamlMappingNode' to type 'YamlDotNet.RepresentationModel.YamlSequenceNode'.
When passing "items" as parameter to YamlScalarNode() it just complains about the item not being there which is to be expected. As I'm not sure where my toughttrain is going wrong I would love a bit assistance on how to troubleshoot this further.

Your question has already been correctly answered, but I would like to point out that your approach is probably not the best one for parsing files. The YamlDotNet.RepresentationModel.* types offer an object model that directly represents the YAML stream and its various parts. This is useful if you are creating an application that processes or generates YAML streams.
When you want to read a YAML document into an object graph, the best approach is to use the Deserializer class. With it you can write your code as follows:
using(var reader = File.OpenText("blueprints.yaml")
{
var deserializer = new Deserializer();
var blueprintsById = deserializer.Deserialize<Dictionary<int, YamlBlueprint>>(reader);
// Use the blueprintsById variable
}
The only difference is that the Id property of the YamlBlueprint instances won't be set, but that's just a matter of adding this:
foreach(var entry in blueprintsById)
{
entry.Value.Id = entry.Key;
}

You have too much stuff going on in one line of code. Create a new YamlScalarNode object in one line, access the array in another line, cast the resultant object in another line. That way, you'll narrow down the problem area to a single step.
The message is telling you that you are retrieving a YamlMappingNode from the array but you are casting it to a YamlSequenceNode. Which is not allowed since the two types are obviously not related.

Well that was kinda stupid... it's kind of hard to create an mapping of something which only contains one element. I've edited the repo linked in the OP with an working example in case somebody runs into the same problem.

Related

Recursively remove key from Generic C# Object

I am trying to visualize a C# object which is a SyntaxTree. JSON would be nice, but not required, I am just having a hard time dealing with the VS UI and all the circular references in the object. when I try to use JSON.NET to serialize it, I get a circular reference error. This isn't the first time I have run into a similar problem, but I thought I would work on it for a bit.
I know which keys need to be removed, they are ContainingElement, ContainingNamSpace, ContainingSourceUnit, ContainingType.
I was trying to create a function that could be reused to recursively remove those keys from the object before I pass it to JSON.NET, but I need some help.
public static object removeObjectsByName(object incoming, string WildcardRemove){
List<object newObject = new List<object>();
foreach (var item in incoming)
{
if (subItem.ToString().Contains(WildcardRemove))
{
continue;
}
}
removeObject(newObject);
return newObject;
}
I don't typically do a lot with generic types, but I don't know what all the incoming types of data will be, especially as we call it recursively. Should we create a List, Array, or leave it an object? Here is a sample of what I am looking at:
The root of the object is named tree, I am specifically interested in the Functions which has 61 items in the array. As you dig into those you start to find the Containing* keys that need to be removed. Trouble is that they will also exist under Body and Properties. Then under Body, there is another Properties which will have it's Containing*.
I don't need any of that back referencing stuff, I just want each child without any keys named Containing*.
Any tips? Again, I don't care if the output is JSON, to the Console, as a List, if we use Linq or what, just trying to see my way through this.

How to use a 'hard-coded' dictionary/enum

I am wanting to create a 'dictionary' of strings, however I have only ever learned how to use strings to reference what I want in a dictionary. I want something with more auto-correct (as typos can happen in a large table of strings), which is why I want to know how to hard-code. (The value of the strings will be retrieved from a text file, like JSON).
I notice that Microsoft uses some type of hard-coding in their String Resource File.
So instead of doing:
string result = strings["Hello"];
I wish to do this:
string result = strings.Hello;
The only thing I can think of is to use some external tool that creates an enum/struct script with the values from the text file. Is there a better option, perhaps one built into .NET?
Edit: I think 'strongly-typed' would be a better description over 'hard-coded'.
Edit 2: Thanks for all the comments and answers. By the looks of it, some code-gen is required to fufil this result. I wonder if there's already any tools out there that do this for you (I tried looking but my terminology may be lacking). It doesn't seem too difficult to create this tool.
There are compiletime constants and runtime constants.
Your wish for Autocrrection/Intellisense support requires a compile time constants. Those are the only ones Intellisence, Syntax Highlighting and the Compiler double check for you.
But your requriement of having the values generated from a 3rd party textfile, indicates either a runtime constant or some automatic code generation. Runtime constants would take away the Editor support. While Code generation would run into issue with the Editor only having a old copy of the file. And a high risk of breaking tons of code if a string in that one file changes.
So your two requirements are inherently at odds. You need to have your cake and eat it too.
Perhaps my primitve solution to the Enum/ToString() problem might help you?
Enumeration are for most parts groups of constants, and integer ones by default. With added type checks on assignments. That makes them a good way around Primitive Obsession. You reference a value from the group like you would any constant, readonly static field or readonly property. (There is other advantages like Flags, but I doubt they mater here).
While Enums have a string you could use for display and input parsing - the one you use in sourcecode - that one is absolutely not suited for display. By default they are all-caps and you would need to support Localisation down the line. My primitive Solution was a translation layer. I add a Dictionary<someEnum, String> SomeEnumStringRepresentation. This dictionary can be generated and even changed at runtime:
I need to display any specific value, it is SomeEnumLocalisation[someEnum]. I could add a default behavior to just ToString() the compiler representation of the Enum.
I need to parse a user input? Itterate over the values until you find a match, if not throw a ParseException.
I get to use compile time checks. Without having to deal with the very inmutable compile side strings anywhere else. Or with my code side strings changing all the time.
i am not quit understand what out put you want , bu I am just throwing an idea to here - how about to extend the class string and add your own methods to it ? so when you use strings.Hello it will return what you wanted?
example :
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods

Passing pickle strings between C# and IronPython

I wrote an IronPython package to do some data-crunching, and now I am wrapping it in a C# application. Part of the application's functionality is to save the state of a project, and then later to restore that saved state.
I am using the pickle module in IronPython to save an object of a class from my custom package. Before I did the wrapping in C#, that was no problem: I used the pickle.dump() function to serialize the object to a file. Now I want to use the pickle.dumps() function to serialize the object to a string, then pass that string to a C# object and serialize THAT object with an XmlSerializer.
Serialization seems to work, but deserialization breaks down: C# gets the deserialized string and passes it to IronPython, which should be able to reconstitute the original object with the pickle.loads() function, but instead raises this error:
System.Collections.Generic.KeyNotFoundException {"ô"}
Can you help me solve this problem? I have two theories:
Perhaps there is a difference in the string encodings between IronPython and C#, or between C#, IronPython, and what is expected by the pickle module?
Not the entire string is being serialized in the first place, so I am just passing nonsense to pickle.loads()
My evidence that leads me to these theories:
The missing key in the error message (ô) looks like a bit of unicode-parsed-as-ASCII-text.
If I break execution (in debug mode of Visual Studio 2010) and look at the string before it is passed to IronPython for unpicking, what I see is not long enough to represent the entire object. But it might just reach the limit of what the Visual Studio debugger will display.
Thanks in advance!
Short answer: pickling with protocol=-1 works for me where the default, human-readable protocol does not.
Long answer: It looks like theory #1 is substantially correct. I use a dictionary of large numpy arrays to store my data, and even using the default "human-readable" pickling protocol, they are pickled to a binary-like form. Notice the fourth line from the bottom (this is pulled from a pickled file that can be successfully unpickled, but it gives an idea of what I see in the files that can't):
(g10
(I0
tp25
g12
tp26
Rp27
(I1
(I2
tp28
g19
I00
Vq=\u000a×£°(#R¸\u2026ëQ.#
p29
tp30
bssb.
There is the potential for this to cause an error somewhere in the chain of
pickling to a string in IronPython
passing that string to a C# object
serializing that object with an XmlSerializer
unserializing the xml to get back a C# object
passing the string that represents the pickled object back to IronPython
unpicking the string in IronPython
Exactly where the error occurs, I don't yet know. I have worked around the problem by pickling the IronPython object with protocol=-1, which turns the object into a string of binary gibberish that can survive the process.

Setting ComplexType in MathLink

I have another one. I tried to use ml.ComplexType = System.Type.GetType("Complex"); in C# with the Mathematica MathLink, but when I tried to read the numbers with GetComplexArray, it threw an exception stating that I must use the method IMathLink.SetComplexType(), which does not appear to exist.
Is there any way to do this without parsing strings, since I can't for the life of me do that correctly?
The documentation for SetComplexType is here: http://reference.wolfram.com/mathematica/NETLink/ref/SetComplexType.html. You can also find this by pasting "NETLink/ref/SetComplexType" into the Mathematica documentation center. Both these sources indicate that you must execute Needs["NETLink]" prior to use in Mathematica.
For anyone else's reference, I discovered the answer to this one on my own.
What you do is create a dummy instance of any class that has the necessary properties/methods (such as System.Numerics.Complex), here named myVar. Now assuming ml is an instance of IKernelLink, call
ml.ComplexType = myVar.GetType();
You can then use ml.GetComplex() or ml.GetComplexArray().

Debugger Visualizer to generate Object Initializer code

We have a bug to fix, and like any good TDD practitioner, I want to write a failing test to represent the bug first. The bug is in a method that takes a rather complex type as input. The bug will only reproduce when the complex type has a certain combination of property values set.
So far I have reproduced the bug and, in the debugger, can view the run-time value of the complex type. Now I need to create that complex type in the "Arrange" section of my unit test so that I can feed it to the buggy method in the "Act" section of the unit test.
I can write a big object initializer code block, by hand, such as the following one:
var cats =
new List<Cat>
{
new Cat {Name = "Sylvester", Age = 8},
new Cat {Name = "Whiskers", Age = 2}
};
or even something like this:
var cats = new List<Cat>();
var cat1 = new Cat();
cat1.Name = "Sylvester";
cat1.Age = 8;
cats.Add(cat1);
var cat2 = new Cat();
cat2.Name = "Whiskers";
cat2.Age = 2;
cats.Add(cat2);
Nothing fancy there. The only problem is the "by hand" part -- the complex type in my case is not nearly as trivial as the above example.
I can also view the object, while in the debugger, with any of the built-in debugger visualizers. So I figured I would write a custom Debugger Visualizer that will generate the object initialization code for me. To use it, I would reproduce the issue in the debugger, pull up the QuickWatch window and select my custom visualizer.
Another option would be to write a custom serialization implementation that would "serialize" to a block of object initialization code. To use this would be a bit harder than just pulling up the QuickWatch window, but this could work.
Before I tackle this problem myself, has anybody done something like this? Mind sharing a code snippet? Or would anyone suggest another approach?
P.S. In my case, the type of the object is a subclass of an abstract base class. Just wanted to mention it.
Here is a tool called Object Exporter which does exactly what you are looking for, it will generate C# initialization code from any object in your debugging windows:
https://visualstudiogallery.msdn.microsoft.com/c6a21c68-f815-4895-999f-cd0885d8774f
Blog Post with more information:
http://www.omarelabd.net/exporting-objects-from-the-visual-studio-debugger/
These suggestions aren't going to work. Read the first line:
You can write a custom visualizer for
an object of any managed class except
for Object or Array.
http://msdn.microsoft.com/en-us/library/e2zc529c.aspx
There is your answer. If I'm reading correctly it can't be implemented through a visualizer. Sort of lame.
I don't know of any existing feature / functionality which provides the behavior you are looking for. But the idea of writing a Visualizer to generate the code for a given object seems sound for simple object types: those consisting of properties of primitive types. Once you get beyond that the task grows increasingly difficult.
In the visualizer you'll have access to the object in question and can use tricks like reflection to get at the members. Reperesenting a member's value as code is easy for primitive types: int, string, etc .... This is much harder for non-primitive types because the process becomes recursive and you need to consider object cycles.
If this does work for you here's a quick tutorial on Debugger Visualizers
http://blogs.msdn.com/b/lior/archive/2009/05/31/creating-a-debugger-visualizer-for-visual-studio-c-tutorial.aspx
All in all it may be easier to just hand write up each scenario :(

Categories