How to simulate the printing of object like in C# Interactive Console? - c#

An example:
If we type scoreDir in the C# Console, its content is pretty printed, i.e. the definition of the object, its length and its data.
I would like to simulate this printing with a built-in .NET method, e.g. ToString(). However, ToString() doesn't work, as showed. "Simulate" means I can generate the same printed string, but store it in a variable. Microsoft must have used some function to print such object; it's best to just re-use the function (no re-inventing the wheels).

Credits to #Hans Passant in the comment section.
In Visual Studio, after installing the Nuget package Microsoft.CodeAnalysis.CSharp.Scripting, the static function Microsoft.CodeAnalysis.CSharp.Scripting.Hosting.CSharpObjectFormatter.Instance.FormatObject() can be used to mimic the same output as C# Interactive Console.
Here is the code that works:
using System;
using System.IO;
using System.Collections.Concurrent;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var scoreDir = new ConcurrentDictionary<(int, int), (double, int)>();
scoreDir.TryAdd((1, 2), (0.9, 3));
var res = Microsoft.CodeAnalysis.CSharp.Scripting.Hosting.CSharpObjectFormatter.Instance.FormatObject(scoreDir);
Console.WriteLine(res);
}
}
}
Result:

There is no such build tool for this but you can convert it to Json. The problem with your example that is not so easy for a ConcurrentDictionary.
IMPORTANT NOTE:
This only will work for Newtonsoft and .NET 6.0 since System.Text.Json does not provide a cast for serialize to JSON ConcurrentDictionary and this also don't work for Newtonsoft in .NET Framework
How to Serialize to JSON string a ConcurrentDictionary?
Import Newtonsoft.Json from Nugget
Add using Newtonsoft.Json; to the references in the head of the file
ConcurrentDictionary<(int,int), (double,int)> scoreDir = new ConcurrentDictionary<(int,int), (double,int)>();
scoreDir.TryAdd((1,2),(0.9,3));
string jsonString = JsonConvert.SerializeObject(scoreDir);
Console.WriteLine(jsonString);
Returns:
{"(1, 2)":{"Item1":0.9,"Item2":3}}
Fiddle: https://dotnetfiddle.net/XzHHoN

Related

My System.CommandLine app won't build! It can't find a CommandHandler. Do I need to write it?

I am using VS 2022, .Net 6.0, and trying to build my first app using System.CommandLine.
Problem: when I build it, I get an error
The name 'CommandHandler' does not exist in the current context
The code I'm trying to build is the sample app from the GitHub site: https://github.com/dotnet/command-line-api/blob/main/docs/Your-first-app-with-System-CommandLine.md , without alteration (I think).
It looks like this:
using System;
using System.CommandLine;
using System.IO;
static int Main(string[] args)
{
// Create a root command with some options
var rootCommand = new RootCommand
{
new Option<int>(
"--int-option",
getDefaultValue: () => 42,
description: "An option whose argument is parsed as an int"),
new Option<bool>(
"--bool-option",
"An option whose argument is parsed as a bool"),
new Option<FileInfo>(
"--file-option",
"An option whose argument is parsed as a FileInfo")
};
rootCommand.Description = "My sample app";
// Note that the parameters of the handler method are matched according to the names of the options
rootCommand.Handler = CommandHandler.Create<int, bool, FileInfo>((intOption, boolOption, fileOption) =>
{
Console.WriteLine($"The value for --int-option is: {intOption}");
Console.WriteLine($"The value for --bool-option is: {boolOption}");
Console.WriteLine($"The value for --file-option is: {fileOption?.FullName ?? "null"}");
});
// Parse the incoming args and invoke the handler
return rootCommand.InvokeAsync(args).Result;
}
I have installed the latest version of System.Commandline: 2.0.0-beta2.21617.1
SURELY I am just being a big fat idiot in some respect. But I don't see it.
Any insight would be welcomed.
This issue is caused by updating the CommandLine 2.0 Beta 2 package. Add the reference System.CommandLine.NamingConventionBinder to the references to fix the problem. Follow the announcements on command-line-api's GitHub account:
In your project, add a reference to System.CommandLine.NamingConventionBinder.
In your code, change references to the System.CommandLine.Invocation namespace to
use System.CommandLine.NamingConventionBinder, where the CommandHandler.Create
methods are now found. (There’s no longer a CommandHandler type in
System.CommandLine, so after you update you’ll get compilation errors until you
reference System.CommandLine.NamingConventionBinder.)
If you want to continue with the old habits, try using older versions of the System.CommandLine package.
References
Announcing System.CommandLine 2.0 Beta 2 and the road to GA
Think you are missing a using line:
using System;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.IO;
I can't swear that's it, but it looks like CommandHandler is defined in a namespace not referenced by a using (in your current code), so System.CommandLine.Invocation may be the key!

PyScope missing in Python .NET

My problem is that I'm trying to use Python.NET inside Visual Studio, I installed Python 3.5, and the python.NET package trough nuget and trough pip too.
added namespace Python.Runtime in my Form application, and the Python.Runtime.dll is there in the references too.
I tried to use a sample code from the offical site: offical site
using Python.Runtime;
// create a person object
Person person = new Person("John", "Smith");
// acquire the GIL before using the Python interpreter
using (Py.GIL())
{
// create a Python scope
using (PyScope scope = Py.CreateScope())
{
// convert the Person object to a PyObject
PyObject pyPerson = person.ToPython();
// create a Python variable "person"
scope.Set("person", pyPerson);
// the person object may now be used in Python
string code = "fullName = person.FirstName + ' ' + person.LastName";
scope.Exec(code);
}
}
The Py.GIL() part works and I already tried to import numpy package and do some basic calculations with it, it worked well.
However the PyScope is just not recognized, nor do Py.CreateScope.
("The type or namespace PyScope could not be found")
Tried to write Python.Runtime.PyScope, tried reinstalling, tried older package, used console app and winforms app too, however nothing seems to work.
Am I missing something here?
I ran into this problem too. Using var instead of PyScope worked for me. As in:
using (var scope = Py.CreateScope())
Edit & Alternative: when I visited the definition of CreateScope(), the output type was PyModule:
public static PyModule CreateScope();
public static PyModule CreateScope(string name);
Using this instead of var also works for me:
using (PyModule scope = Py.CreateScope())
If that doesn't work for you, visiting the definition of the function and using the output type listed in your version likely will.
The var isn't picky though.

.NET Standard F# library does not store non-English characters properly

I create a .NET Standard F# library with F# 4.3.4 (I also tested with 4.5) with the following code:
namespace ClassLibrary2
module Say =
let a = "国".Length.ToString()
let b = sprintf "%A" ("国".ToCharArray() |> Array.map int)
let c = "国"
When referencing that library from another project (.net core or .net framework):
Console.WriteLine(Say.a); // F# .net standard
Console.WriteLine(Say.b);
Console.WriteLine(Say.c == "国");
I get the following output:
2
[|65533; 65533|]
False
The equivalent C# .NET Standard library:
using System;
using System.Linq;
namespace ClassLibrary1
{
public static class Class1
{
public static string a = "国".Length.ToString();
public static string b = String.Join(", ", "国".ToCharArray().Select(i => ((int)i).ToString()));
public static string c = "国";
}
}
gives the expected output:
1
22269
True
Here's a repo showing the issue: https://github.com/liboz/Kanji-Bug.
This looks likely to be a bug, but I was wondering what would be a reasonable workaround for this problem? Specifically, I want to be able to be able to check equality for strings with something like Say.c = "国" where I might be using non-English characters while using a .NET Standard library.
So, the issue appears to be that the first file that the dotnet cli generates in an F# library does not use Unicode for its encoding. So, when creating a .NET Standard F# library that file for me was generated with Shift-JIS encoding, likely due to region settings on my own computer. Therefore, the solution to my issue was to simply save the default Library1.fs file with UTF-8 encoding manually so that it would have the same encoding as all the other files.

How to use referenced c# dll code in a VS C# console application

So I have two dlls, Algorithms.dll and Data_Structures.dll (I made these from projects I found on GitHub). Using the browse feature I have managed to add both of the DLL files as references to my Visual Studio 2017 console project. The problem is I can't do anything else with them. Whenever I try to reference something within either file, it simply cannot be found. The only thing that is recognized is the namespace, but nothing inside of that.
What do I need to do to get VS to find the classes these DLLs contain so I can use them? I am aware I need to use Algorithms.Sorting for the example but I can't call anything so I used this as an example.
P.S. If you need more info, please ask. I'm not sure what's relevant to this issue.
EDIT: Ok, it was misleading to have that kind of example. Corrected but please read the question.
EDIT: I tried this on Monodevelop and get the same issue. Maybe it's not the IDE that's the problem?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Algorithms.Sorting; // Error, Sorting cannot be found, and neither can the file container Sorting
using Data_Structures; //Perfectly ok, can find the namespace
namespace CS_HW2_Testing_App
{
class Program
{
static void Main(string[] args)
{
// I'd like to call MergeSort and so forth here. What am I missing?!
}
}
}
Here's the top piece of the file containing MergeSort if it helps
using System;
using System.Collections.Generic;
using Algorithms.Common;
namespace Algorithms.Sorting
{
public static class MergeSorter
{
//
// Public merge-sort API
public static List<T> MergeSort<T>(this List<T> collection, Comparer<T> comparer = null)
{
comparer = comparer ?? Comparer<T>.Default;
return InternalMergeSort(collection, 0, collection.Count - 1, comparer);
}
...
In the first code block, you're importing the wrong namespace: using Algorithms.MergeSort should be using Algorithms.Sorting. Then you can use MergeSorter.MergeSort<T>(...) in your code!
You need to reference the namespace not the class.
using Algorithms.Sorting; //instead of using Algorithms.MergeSort;
Plus make sure the classes are public

Json with C# and Mono

I'm trying to read a json string into memory and get this undocumented error msg
$ mcs -r:FortnoxAPILibrary.dll -r:npgsql.dll -r:System.Data.dll -r:Newtonsoft.Json.dll Vouchers.cs
Vouchers.cs(44,18): error CS0103: The name `JArray' does not exist in the current context
Compilation failed: 1 error(s), 0 warnings
My code is
var json = System.IO.File.ReadAllText("test.json");
var objects = JArray.Parse(json); // parse as array
foreach(JObject root in objects)
{
foreach(KeyValuePair<String, JToken> app in root)
{
var appName = app.Key;
var description = (String)app.Value["Description"];
var value = (String)app.Value["Value"];
Console.WriteLine(appName);
Console.WriteLine(description);
Console.WriteLine(value);
Console.WriteLine("\n");
}
}
Where is it documented how this should work?
You are more than likely missing a using statement.
using Newtonsoft.Json.Linq;
Every piece of C# code you write, except for core types, requires a using statement pointing to any dependencies.
C# libraries often don't document the using statement requirements for a block of code. Maybe an oversight, but most users are using an IDE, which warns of the missing statement and offers options to automatically insert them.
It is not documented that I must include this line.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

Categories

Resources