Error reading JObject from JsonReader. Current JsonReader item is not an object in C# - c#-4.0

I have written a piece of code to get a value from a currency converter like below:
WebClient n = new WebClient();
var JsonData = n.DownloadString("http://currencyconverterapi.com/api/v6/convert?q=USD_NRI&compact=ultra&apiKey=");
JsonData = {"USD_INR":69.657026} // Got value result from JsonData
dynamic JObj = JObject.Parse(JsonData);
dynamic JOresult = JObject.Parse(Convert.ToString(JObj.USD_INR)); //Got Error here (Error reading JObject from JsonReader. Current JsonReader item is not an object: Float. Path '', line 1, position 9.)
string JOFilter_Val = Convert.ToString(JOresult.val);
decimal Total = 230 * Convert.ToDecimal(JOFilter_Val);
return Total;
I want to get the value '69.657026' from multiplying with the decimal 230, and return the final result. Can anybody tell me what I'm doing wrong and if possible please correct it?

It's not really clear why you're trying to parse 69.657026 as a JObject - it's not an object.
I suspect you don't need to do that at all - just use JObj.USD_INR as a decimal:
decimal value = JObj.USD_INR; // Use the dynamic conversion to handle this
In general you seem to be converting back and forth far more than you need to. Here's a complete example of what I think you're trying to do:
using Newtonsoft.Json.Linq;
using System;
class Test
{
static void Main()
{
string json = "{ \"USD_INR\": 69.657026 }";
dynamic obj = JObject.Parse(json);
decimal rate = obj.USD_INR;
decimal total = 230 * rate;
Console.WriteLine(total); // 16021.115980
}
}
Alternatively, without dynamic typing:
using Newtonsoft.Json.Linq;
using System;
class Test
{
static void Main()
{
string json = "{ \"USD_INR\": 69.657026 }";
JObject obj = JObject.Parse(json);
decimal rate = (decimal) obj["USD_INR"];
decimal total = 230 * rate;
Console.WriteLine(total);
}
}

Related

How do I round to two decimal places on MPAndroidChart?

I've made a line chart on MPAndroidChart and would like the output to only show two decimal places.
This is the code I've used to round off the data. The data was originally in a Long ArrayList. I converted it to float because Android Studio wanted it to be in float.
private static final DecimalFormat df = new DecimalFormat("0.00");
ArrayList<Entry> dataVals = new ArrayList<Entry>();
for (i=0; i<sampleSize; i++){
float k = list.get(i)/1000;
df.setRoundingMode(RoundingMode.UP);
df.format(k);
dataVals.add(new Entry((float) (i), k));
}
The datapoints sometimes show two decimal places and sometimes three. I can't work out why.
Does anyone know how to ensure it always rounds off to decimal places?
// Create a custom ValueFormatter that rounds to two decimal places
ValueFormatter formatter = new ValueFormatter() {
#Override
public String getFormattedValue(float value) {
return String.format(Locale.getDefault(), "%.2f", value);
}
};
// Set the ValueFormatter on the chart
chart.getAxisLeft().setValueFormatter(formatter);
If you want to control the formatting of the numbers displayed over each data point, you have to define a value formatter on the data set (not the axis - which controls the format of the numbers on the chart axes). For example, to show 2 decimal places for all points, you would add this (using your existing decimal formatter df):
dataSet.setValueFormatter(new ValueFormatter() {
#Override
public String getFormattedValue(float value) {
return df.format(value);
}
});
A more complete example:
// declare the formatter as a class member
private static final DecimalFormat df = new DecimalFormat("0.00");
// Prepare your list of Entries (no need to do anything with the
// formatter here)
ArrayList<Entry> dataVals = new ArrayList<Entry>();
for (i=0; i<sampleSize; i++){
float k = list.get(i)/1000;
dataVals.add(new Entry((float) (i), k));
}
// set the formatter mode (only need to call this once,
// not inside the loop)
df.setRoundingMode(RoundingMode.UP);
// create a LineDataSet from your list of entries
LineDataSet dataSet = new LineDataSet(dataVals, "Values");
// Set a value formatter on the data set (to control
// how the numbers over the points are shown) and
// call your data formatter here
dataSet.setValueFormatter(new ValueFormatter() {
#Override
public String getFormattedValue(float value) {
return df.format(value);
}
});
Note You can also define this formatter on the LineData object instead of the LineDataSet if you have multiple data sets and want to apply the same formatter to all of them. The syntax is the same as setting it on the LineDataSet.
LineData data = new LineData(dataSet);
data.setValueFormatter(new ValueFormatter() {
#Override
public String getFormattedValue(float value) {
return df.format(value);
}
});

Generic Template String like in Python in Dart

In python, I often use strings as templates, e.g.
templateUrl = '{host}/api/v3/{container}/{resourceid}'
params = {'host': 'www.api.com', 'container': 'books', 'resourceid': 10}
api.get(templateUrl.format(**params))
This allows for easy base class setup and the like. How can I do the same in dart?
I'm assuming I will need to create a utility function to parse the template and substitute manually but really hoping there is something ready to use.
Perhaps a TemplateString class with a format method that takes a Map of name/value pairs to substitute into the string.
Note: the objective is to have a generic "format" or "interpolation" function that doesn't need to know in advance what tags or names will exist in the template.
Further clarification: the templates themselves are not resolved when they are set up. Specifically, the template is defined in one place in the code and then used in many other places.
Dart does not have a generic template string functionality that would allow you to insert values into your template at runtime.
Dart only allows you to interpolate strings with variables using the $ syntax in strings, e.g. var string = '$domain/api/v3/${actions.get}'. You would need to have all the variables defined in your code beforehand.
However, you can easily create your own implementation.
Implementation
You pretty much explained how to do it in your question yourself: you pass a map and use it to have generic access to the parameters using the [] operator.
To convert the template string into something that is easy to access, I would simply create another List containing fixed components, like /api/v3/ and another Map that holds generic components with their name and their position in the template string.
class TemplateString {
final List<String> fixedComponents;
final Map<int, String> genericComponents;
int totalComponents;
TemplateString(String template)
: fixedComponents = <String>[],
genericComponents = <int, String>{},
totalComponents = 0 {
final List<String> components = template.split('{');
for (String component in components) {
if (component == '') continue; // If the template starts with "{", skip the first element.
final split = component.split('}');
if (split.length != 1) {
// The condition allows for template strings without parameters.
genericComponents[totalComponents] = split.first;
totalComponents++;
}
if (split.last != '') {
fixedComponents.add(split.last);
totalComponents++;
}
}
}
String format(Map<String, dynamic> params) {
String result = '';
int fixedComponent = 0;
for (int i = 0; i < totalComponents; i++) {
if (genericComponents.containsKey(i)) {
result += '${params[genericComponents[i]]}';
continue;
}
result += fixedComponents[fixedComponent++];
}
return result;
}
}
Here would be an example usage, I hope that the result is what you expected:
main() {
final templateUrl = TemplateString('{host}/api/v3/{container}/{resourceid}');
final params = <String, dynamic>{'host': 'www.api.com', 'container': 'books', 'resourceid': 10};
print(templateUrl.format(params)); // www.api.com/api/v3/books/10
}
Here it is as a Gist.
Here is my solution:
extension StringFormating on String {
String format(List<String> values) {
int index = 0;
return replaceAllMapped(new RegExp(r'{.*?}'), (_) {
final value = values[index];
index++;
return value;
});
}
String formatWithMap(Map<String, String> mappedValues) {
return replaceAllMapped(new RegExp(r'{(.*?)}'), (match) {
final mapped = mappedValues[match[1]];
if (mapped == null)
throw ArgumentError(
'$mappedValues does not contain the key "${match[1]}"');
return mapped;
});
}
}
This gives you a very similar functionality to what python offers:
"Test {} with {}!".format(["it", "foo"]);
"Test {a} with {b}!".formatWithMap({"a": "it", "b": "foo"})
both return "Test it with foo!"
It's even more easy in Dart. Sample code below :
String host = "www.api.com"
String container = "books"
int resourceId = 10
String templateUrl = "$host/api/v3/$container/${resourceId.toString()}"
With the map, you can do as follows :
Map<String, String> params = {'host': 'www.api.com', 'container': 'books', 'resourceid': 10}
String templateUrl = "${params['host']}/api/v3/${params['container']}/${params['resourceId']}"
Note : The above code defines Map as <String, String>. You might want <String, Dynamic> (and use .toString())
Wouldn't it be simplest to just make it a function with named arguments? You could add some input validation if you wanted to.
String templateUrl({String host = "", String container = "", int resourceid = 0 }) {
return "$host/api/v3/$container/$resourceId";
}
void main() {
api.get(templateUrl(host:"www.api.com", container:"books", resourceid:10));
}

YamlDotNet !!binary type

I am trying to send binary data, i.e. byte arrays, using yaml. According to the yaml documentation, Yaml Binary Type, this is supported. On the Java side I use SnakeYaml and if a value of byte[] is passed, then the yaml correctly gives !!binary.
This functionality does not seem to be supported "out of the box" in YamlDotNet. The below code snippet creates a sequence of integer values:
IDictionary<string, object> data = new Dictionary<string, object>();
const string value = ":| value: <XML> /n\n C:\\cat";
byte[] bytes = Encoding.UTF8.GetBytes(value);
data.Add(ValueKey, bytes);
// Turn the object representation into text
using (var output = new StringWriter())
{
var serializer = new Serializer();
serializer.Serialize(output, data);
return output.ToString();
}
Output like:
val:\r- 58\r- 124\r- 32\r- 118\r- 97\r- 108\r- 117\r- 101\r- 58\r- 32\r- 60\r- 88\r- 77\r- 76\r- 62\r- 32\r- 47\r- 110\r- 10\r- 32\r- 67\r- 58\r- 92\r- 99\r- 97\r- 116\r
But I would like something more like:
val: !!binary |-
OnwgdmFsdWU6IDxYTUw+IC9uCiBDOlxjYXQ=
Can anyone recommend a workaround?
The preferred way to add support for custom types is to use a custom IYamlTypeConverter. A possible implementation for the !!binary type would be:
public class ByteArrayConverter : IYamlTypeConverter
{
public bool Accepts(Type type)
{
// Return true to indicate that this converter is able to handle the byte[] type
return type == typeof(byte[]);
}
public object ReadYaml(IParser parser, Type type)
{
var scalar = (YamlDotNet.Core.Events.Scalar)parser.Current;
var bytes = Convert.FromBase64String(scalar.Value);
parser.MoveNext();
return bytes;
}
public void WriteYaml(IEmitter emitter, object value, Type type)
{
var bytes = (byte[])value;
emitter.Emit(new YamlDotNet.Core.Events.Scalar(
null,
"tag:yaml.org,2002:binary",
Convert.ToBase64String(bytes),
ScalarStyle.Plain,
false,
false
));
}
}
To use the converter in the Serializer, you simply need to register it using the following code:
var serializer = new Serializer();
serializer.RegisterTypeConverter(new ByteArrayConverter());
For the Deserializer, you also need to register the converter, but you also need to add a tag mapping to resolve the !!binary tag to the byte[] type:
var deserializer = new Deserializer();
deserializer.RegisterTagMapping("tag:yaml.org,2002:binary", typeof(byte[]));
deserializer.RegisterTypeConverter(new ByteArrayConverter());
A fully working example can be tried here
For anyone that's interested.... I fixed this by creating the string myself and adding the !!binary tag, and also doing some clean up. Below is the code.
ToYaml:
IDictionary<string, string> data = new Dictionary<string, string>();
string byteAsBase64Fromat = Convert.ToBase64String("The string to convert");
byteAsBase64Fromat = "!!binary |-\n" + byteAsBase64Fromat + "\n";
data.Add(ValueKey, byteAsBase64Fromat);
string yaml;
using (var output = new StringWriter())
{
var serializer = new Serializer();
serializer.Serialize(output, data);
yaml = output.ToString();
}
string yaml = yaml.Replace(">", "");
return yaml.Replace(Environment.NewLine + Environment.NewLine, Environment.NewLine);
And then back by:
string binaryText = ((YamlScalarNode)data.Children[new YamlScalarNode(ValueKey)]).Value
String value = Convert.FromBase64String(binaryText);

Haxe Int to String

It seems AS3 has a toString() for the Number class. Is there an equivalent in Haxe? The only solution I could come up with for converting an Int to a String is a function like:
public function IntToString(i:Int):String {
var strbuf:StringBuf = new StringBuf();
strbuf.add(i);
return strbuf.toString();
}
Is there a better method that I'm overlooking?
You don't usually need to manually convert an int to a string because the conversion is automatic.
var i = 1;
var s = "" + i; // s is now "1"
The "formal" way to convert any value to a string is to use Std.string():
var s = Std.string(i);
You could also use string interpolation:
var s = '$i';
The function your wrote is fine but definitely overkilling.

How can I call GC.GetGeneration() using a string as the object name?

I'm using Reflection to get all the fields of my class in c#, but now I want to get the GC Generation of each variable in my class. How can I do this?
CSkyclass
{
float time = 0;
}
Sky = new CSkyclass();
void GetGeneration()
{
FieldInfo[] FieldArray = typeof(CSkyclass).GetFields(flags);
foreach(System.Reflection.FieldInfo Field in FieldArray)
{
string name = Field.Name; //"time"
int g = GC.GetGeneration(name); //should = GC.GetGeneration(Sky.time);
}
}
Is this even possible?
Thanks
You're trying to get the generation of the field's value:
GC.GetGeneration(field.GetValue(someInstance));

Resources