I'm trying to find a way to initialize a Dictionary inline in ActionScript 3, like:
private var sampleDic:Dictionary = new Dictionary (
{ "zero", "Hello" },
{ "one", "World" }
);
I tried many ways, but none works. Anyone knows if it's possible, and how?
Thanks
No, you can't do it. You have to construct a dictionary and then add the values in a loop or individually.
If it's static you can do this with a block
private static var myDict:Dictionary = new Dictionary();
{
myDict["zero"] = "Hello";
myDict["one"] = "World";
}
If you REALLY want something like that, you can use a Dictionary factory:
public class DictFactory
{
public var dict:Dictionary;
public function create(obj:Object):Dictionary
{
dict = new Dictionary();
for (var key:String in obj) {
dict[key] = obj[key];
}
return dict;
}
}
Usage:
private var sampleDic:Dictionary = new DictFactory().create({ "zero":"Hello", "one": "World" });
The DictFactory.create expects a Object with key-values, that will be applied to the returned Dictionary, if you pass any other object (in AS3, any class is Object), results may be undesireable. :)
You can extend dictionary class and override default constructor with one that accepts initial key-value pears.
EDIT:
You can also use this dirty JS like solution :)
import flash.utils.Dictionary;
var dict : Dictionary = function ( d : Dictionary, p : Object ) : Dictionary { for ( var i : String in p ) { d[i] = p[i] }; return d; }(new Dictionary(), {
"zero": "Hello",
"one": "World"
})
trace( dict["zero"] );
If there is no specific reason to use a Dictionary you can do it with an object.
private var sample:Object = {
"zero": "Hello",
"one": "World"
};
Related
I am using Json.net in my MVC 4 program.
I have an object item of class Item.
I did:
string j = JsonConvert.SerializeObject(item);
Now I want to add an extra property, like "feeClass" : "A" into j.
How can I use Json.net to achieve this?
You have a few options.
The easiest way, as #Manvik suggested, is simply to add another property to your class and set its value prior to serializing.
If you don't want to do that, the next easiest way is to load your object into a JObject, append the new property value, then write out the JSON from there. Here is a simple example:
class Item
{
public int ID { get; set; }
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
Item item = new Item { ID = 1234, Name = "FooBar" };
JObject jo = JObject.FromObject(item);
jo.Add("feeClass", "A");
string json = jo.ToString();
Console.WriteLine(json);
}
}
Here is the output of the above:
{
"ID": 1234,
"Name": "FooBar",
"feeClass": "A"
}
Another possibility is to create a custom JsonConverter for your Item class and use that during serialization. A JsonConverter allows you to have complete control over what gets written during the serialization process for a particular class. You can add properties, suppress properties, or even write out a different structure if you want. For this particular situation, I think it is probably overkill, but it is another option.
Following is the cleanest way I could implement this
dynamic obj = JsonConvert.DeserializeObject(jsonstring);
obj.NewProperty = "value";
var payload = JsonConvert.SerializeObject(obj);
You could use ExpandoObject.
Deserialize to that, add your property, and serialize back.
Pseudocode:
Expando obj = JsonConvert.Deserializeobject<Expando>(jsonstring);
obj.AddeProp = "somevalue";
string addedPropString = JsonConvert.Serializeobject(obj);
I think the most efficient way to serialize a property that doesn't exist in the type is to use a custom contract resolver. This avoids littering your class with the property you don't want, and also avoids the performance hit of the extra serialization round trip that most of the other options on this page incur.
public class SpecialItemContractResolver : DefaultContractResolver {
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) {
var list = base.CreateProperties(type, memberSerialization);
if (type.Equals(typeof(Item))) {
var feeClassProperty = CreateFeeClassProperty();
list.Add(feeClassProperty);
}
return list;
}
private JsonProperty CreateFeeClassProperty() {
return new JsonProperty {
PropertyName = "feeClass",
PropertyType = typeof(string),
DeclaringType = typeof(Item),
ValueProvider = new FeeClassValueProvider(),
AttributeProvider = null,
Readable = true,
Writable = false,
ShouldSerialize = _ => true
};
}
private class FeeClassValueProvider : IValueProvider {
public object GetValue(object target) => "A";
public void SetValue(object target, object value) { }
}
}
To use this functionality:
// This could be put in a static readonly place so it's reused
var serializerSettings = new JsonSerializerSettings {
ContractResolver = new SpecialItemContractResolver()
};
// And then to serialize:
var item = new Item();
var json = JsonConvert.Serialize(item, serializerSettings);
how to pass a values dynamically to an Marionette.CompositeView during run time? like in java we create a method like the following
package com.test.poc;
public class SampleMethod {
public int add(int a, int b) {
return a + b;
}
public static void main(String[] args) {
SampleMethod method = new SampleMethod();
int firstValue = 90, secondValue = 90;
System.out.println("add : " + method.add(firstValue, secondValue));
}
}
the above is the simple java code anybody can understand like the above how to create and pass arguments to Marionette.CompositeView and work on them?
Best Regards
at the moment you instanciate a view, you can pass whatever arguments you want. normally you pass the model and the collection to be rendered in the compositeView, but you can pass more data if you need.
var MyCompositeView = Backbone.Mationette.CompositeView.extend({
initialize : function (options){
this.dataValue = options.dataValue1;
this.helperObject = options.helperObject;
this.useValues();
},
useValues: function () {
console.log(this.dataValue);
}
});
var helperObject = {
value3 : "I have a value",
value4 : "I dont!"
}; /// a js object literal
var myModel = new MyModel();
var myCollection = new MyCollection();
var myCompositeView = new MyCompositeView({model:myModel,
collection:myCollection,
helperObject:helperObject,
dataValue1:"Hi there"});
notice that Im passing 4 values in the at the time to intanciate the view, and Im reading just two of them, the model and the collection will be handled by marionette, but the other two you can read them in your initialize function.
hope that helps.
I am building an app that uses Open Flash Chart 2. This chart is a flash object that accepts JSON with a specific structure.
"elements": [
{
"type": "bar_stack",
"colours": [
"#F19899",
"#A6CEE3"
],
"alpha": 1,
"on-show": {
"type": "grow-up",
"cascade": 1,
"delay": 0
},
...
I am using a simple anonymous type to return the JSON like so:
return Json(new
{
elements = new [] {
new
{
type = "bar_stack",
colours = colours.Take(variables.Count()),
alpha = 1,
on_show = new
{
type = "grow-up",
cascade = 1,
delay = 0
},
...
}
}
The problem is that several properties (like "on-show") use a dash and obviously I cannot use a dash when naming a property in C# code.
Is there a way to overcome this? Preferably without the need to declare a whole bunch of classes.
You can use a dictionary:
return Json(new {
elements = new [] {
new Dictionary<string, object>
{
{ "type", "bar_stack" },
{ "colours", new [] { "#F19899", "#A6CEE3" } },
{ "alpha", 1 },
{ "on-show", new
{
type = "grow-up",
cascade = 1,
delay = 0
} },
}
}
});
(Written in SO editor; I may have made some syntax errors, but you get the idea....)
Craig's solution is propably better, but in the meantime I implemented this:
public class UnderscoreToDashAttribute : ActionFilterAttribute
{
private readonly string[] _fixes;
public UnderscoreToDashAttribute(params string[] fixes)
{
_fixes = fixes;
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.HttpContext.Response.Filter = new ReplaceFilter(filterContext, s => _fixes.Aggregate(s, (current, fix) => current.Replace(fix, fix.Replace('_', '-'))));
}
public class ReplaceFilter : MemoryStream
{
private readonly Stream _stream;
private readonly Func<string, string> _filter;
public ReplaceFilter(ControllerContext filterContext, Func<string, string> filter)
{
_stream = filterContext.HttpContext.Response.Filter;
_filter = filter;
}
public override void Write(byte[] buffer, int offset, int count)
{
// capture the data and convert to string
var data = new byte[count];
Buffer.BlockCopy(buffer, offset, data, 0, count);
var s = _filter(Encoding.Default.GetString(buffer));
// write the data to stream
var outdata = Encoding.Default.GetBytes(s);
_stream.Write(outdata, 0, outdata.GetLength(0));
}
}
}
Then, if you decorate your action like so:
[UnderscoreToDash("on_show", "grid_colour")]
public JsonResult GetData()
It makes the appropriate "fixes".
P.S. That awesome moment when Resharper changes your code to Linq...
_fixes.Aggregate(s, (current, fix) => current.Replace(fix, fix.Replace('_', '-')))
I am trying to deserialize a JSON string into a class instance in Haxe.
class Action
{
public var id:Int;
public var name:String;
public function new(id:Int, name:String)
{
this.id = id;
this.name = name;
}
}
I would like to do something like this:
var action:Action = haxe.Json.parse(actionJson);
trace(action.name);
However, this produces an error:
TypeError: Error #1034: Type Coercion failed: cannot convert Object#3431809 to Action
Json doesn't have a mechanism to map language specific data types and only supports a subset of the data types included in JS. To keep the information about the Haxe types you can certainly build your own mechanism.
// This works only for basic class instances but you can extend it to work with
// any type.
// It doesn't work with nested class instances; you can detect the required
// types with macros (will fail for interfaces or extended classes) or keep
// track of the types in the serialized object.
// Also you will have problems with objects that have circular references.
class JsonType {
public static function encode(o : Dynamic) {
// to solve some of the issues above you should iterate on all the fields,
// check for a non-compatible Json type and build a structure like the
// following before serializing
return haxe.Json.stringify({
type : Type.getClassName(Type.getClass(o)),
data : o
});
}
public static function decode<T>(s : String) : T {
var o = haxe.Json.parse(s),
inst = Type.createEmptyInstance(Type.resolveClass(o.type));
populate(inst, o.data);
return inst;
}
static function populate(inst, data) {
for(field in Reflect.fields(data)) {
Reflect.setField(inst, field, Reflect.field(data, field));
}
}
}
I extended Franco's answer to allow for recursively containing objects within your json objects, as long as the _explicitType property is set on that object.
For instance, the following json:
{
intPropertyExample : 5,
stringPropertyExample : 'my string',
pointPropertyExample : {
_explicitType : 'flash.geom.Point',
x : 5,
y : 6
}
}
will correctly be serialized into an object whose class looks like this:
import flash.geom.Point;
class MyTestClass
{
public var intPropertyExample:Int;
public var stringPropertyExample:String;
public var pointPropertyExample:Point;
}
when calling:
var serializedObject:MyTestClass = EXTJsonSerialization.decode([string of json above], MyTestClass)
Here's the code (note that it uses TJSON as a parser, as CrazySam recommended):
import tjson.TJSON;
class EXTJsonSerialization
{
public static function encode(o : Dynamic)
{
return TJSON.encode(o);
}
public static function decode<T>(s : String, typeClass : Class<Dynamic>) : T
{
var o = TJSON.parse(s);
var inst = Type.createEmptyInstance(typeClass);
EXTJsonSerialization.populate(inst, o);
return inst;
}
private static function populate(inst, data)
{
for (field in Reflect.fields(data))
{
if (field == "_explicitType")
continue;
var value = Reflect.field(data, field);
var valueType = Type.getClass(value);
var valueTypeString:String = Type.getClassName(valueType);
var isValueObject:Bool = Reflect.isObject(value) && valueTypeString != "String";
var valueExplicitType:String = null;
if (isValueObject)
{
valueExplicitType = Reflect.field(value, "_explicitType");
if (valueExplicitType == null && valueTypeString == "Array")
valueExplicitType = "Array";
}
if (valueExplicitType != null)
{
var fieldInst = Type.createEmptyInstance(Type.resolveClass(valueExplicitType));
populate(fieldInst, value);
Reflect.setField(inst, field, fieldInst);
}
else
{
Reflect.setField(inst, field, value);
}
}
}
}
A modern, macro-based library for this purpose is json2object. It can be used like this:
var parser = new json2object.JsonParser<Action>();
var action:Action = parser.fromJson('{"id": 0, "name": "run"}', "action.json");
Another option, also macro-powered, is tink_json. In this case it's a bit more verbose because it requires you to specifiy how exactly a class should be parsed using #:jsonParse metadata:
#:jsonParse(function(json) return new Action(json.id, json.name))
class Action {
// ...
Parsing is a one-liner:
var action:Action = tink.Json.parse('{"id": 0, "name": "run"}');
This is kinda related to my other question: flex dictionary bug?
The HashMap has a method getValues() which returns an array of values:
protected var map:Dictionary = null;
public function HashMap(useWeakReferences:Boolean = true)
{
map = new Dictionary( useWeakReferences );
}
public function getValues() : Array
{
var values:Array = [];
for (var key:* in map)
{
values.push( map[key] );
}
return values;
}
In my unit test class, I have:
private var map:IMap;
[Before]
public function setUp():void
{
map = new HashMap();
map.put("a", "value A");
map.put("b", "value B");
map.put("c", "value C");
map.put("x", "value X");
map.put("y", "value Y");
map.put("z", "value Z");
}
[Test]
public function testGetValues():void
{
assertEquals(map.getValues(), /*what should I put here*/);
}
the loop for (var key:* in map) iterates the keys of the dictionary map, but it seems its implementation does it in some random way. What is the best way to write a test since I don't know what the array returned by getValues method will contain?
I thought I could do it by calling the sort method, and compare the values, is there a better way to do it?
assertEquals(map.getValues().sort(), "value A,value B,value C,value X,value Y,value Z");
Yes. If I understand your problem properly, you are trying to see if the inserted values are there in the mapValues array you are getting back. You can use the indexOf function on the array and check something like
//start a loop to go through the arrays.
if( mapValues.indexOf("value A") >= 0 )
{
continue;
}
Hope this helps!