I trying to emit dynamic method that sets fields of class by some values and when type of regular field is struct I want to set field with new struct like this: var myStruct = new SomeStruct( );.
But I can't to find default constructor of that struct.
var type = valueForField.GetType ( );
if( type.IsValueType && !type.IsPrimitive && !type.IsEnum )
{
emit
.ldarg_0
.newobj ( type.GetConstructor( Type.EmptyTypes ) )
.stfld ( field );
continue;
}
It fails at line .newobj ( type.GetConstructor( Type.EmptyTypes ) ) because of passing null to newobj function
Can anybody tell me how to emit new structure creation through it default constructor?
Use initobj
.ldarg_0
.ldflda (field)
.initobj (type)
From msdn:
Value types are not usually created using newobj. They are usually allocated either as arguments or local variables, using newarr (for zero-based, one-dimensional arrays), or as fields of objects. Once allocated, they are initialized using Initobj.
Structs can't have a real parameterless constructor. They have an implicit default constructor that's equivalent to default(T).
It seems like the IL equivalent of default(T) is initobj
Unlike Newobj, initobj does not call the constructor method. Initobj is intended for initializing value types, while newobj is used to allocate and initialize objects.
Related
I can't see what's wrong with this code:
var listShoppingCart = Session["ShoppingCart"];
foreach (var item in listShoppingCart)
{
}
I get a red line below the listShoppingCart in the foreach loop. When I hover over the red line, the messages is that Foreach statement cannot operate on variables type 'object' because 'object' does not contain a public definition for 'GetEnumerator'
I declare the list with a session like this:
Session["ShoppingCart"] = new List<Products>();
You need to cast the session object
var listShoppingCart = Session["ShoppingCart"] as List<Products>;
if (listShoppingCart != null)
{
// Do stuff...
}
In the above code, we get the object located in the session at key "ShoppingCart" and cast that object to a List<Products>. If the cast cannot be done, then listShoppingCart will be null.
Because Session is of Type HttpSessionState and this implements ICollection.
Session values are stored in Dictionary<string,object> which implements ICollection. You need to type cast object to appropriate to enumerate over your list.
Given the following example, is it anyhow possible to create a function that can literally reproduce (not only get the reflect.Type) the actual type for further manipulation? I know go is statically typed and although it's very cool that I can pass any struct to a function that defines an interface parameter, is there any chance I can do more the other way around?
I already looked into the reflect package but only found stuff that returned a reflect.Type or reflect.Value. I used the New() method which returned a new reflect.Value - and there I couldn't set any fields. Maybe someone experienced with the reflect package can tell me if this is definitely possible or not - or if there's another way to do it.
package main
import "fmt"
type User struct {
Name string
}
func main() {
user := User{Name:"FooBar"}
DoSomethingGenericWithStruct(user)
}
func DoSomethingGenericWithStruct(i interface{}) {
// access fields of i ...
// or create slice of type of i ([]User) ...
// or instantiate new object of type of i (new User) ...
// ...
}
You would have to pass a pointer to your struct to be able to modify it.
Also keep in mind that using reflection has a high runtime performance cost.
func DoSomethingGenericWithStruct(i interface{}) {
val := reflect.ValueOf(i)
if val.Kind() != reflect.Ptr {
panic("need a pointer")
}
val = val.Elem() // now you can modify it
// add error checking and such, this will panic if it's not a struct or there's no "Name" field
val.FieldByName("Name").SetString("stuff")
}
playground
To create a new element and assign it:
val = val.Elem()
nval := reflect.New(val.Type()).Elem() // create a new struct of the same type
nval.FieldByName("Name").SetString("stuff")
val.Set(nval)
to modify the actual struct, not reflect.Value, you will have to get the interface{} to it then assert it to your type, for example:
nval := reflect.New(val.Type()).Elem() // create a new struct of the same type
user := nval.Interface().(User)
user.Name = "Stuff"
val.Set(reflect.ValueOf(user))
I have a QHash<QString, myClass*> objects and in order to insert I did the following:
myClass *value = objects.value(key);
if(!value) {
value = new myClass;
objects.insert(key, value);
}
Is this right approach?
Your solution is one of several possible correct approaches.
I usually do it like this as I find it a bit more readable
if( !objects.contains( key ) )
{
objects.insert( key, new MyClass );
}
MyClass* value = objects.value( key);
As already suggested by Marek R, you can use smart pointers for easier memory management:
QHash< QString, QSharedPointer< MyClass > > objects;
// ...
QSharedPointer< MyClass > value = objects.value( key );
Since C++11, I prefer using std::shared_ptr.
This allows you to not care about delete calls; just make sure you always use QSharedPointer< MyClass > instead of MyClass* everywhere. Also, you mustn't use shared pointers for QObject subclasses which have a parent, as the parent object will store a regular pointer for it.
Is it possible to pass a parameter to a method ByRef (or out etc) in ActionScript 3?
I have some globally scoped variables at the top of my class and my method will populate that variable if it's == null.
I'm passing in the variable which needs to be populated but so far my efforts have returned a locally populated variable leaving the globally scoped version of it still null.
The variable being passed to my method varies so I can't hardcode it in my method and simply set it.
ActionScript 3 passes params by reference by default, like Java - except for primitive types. But what you are trying to have it do isn't passing by reference. The parameter passed in is a reference to an object(in the case when it's not a primitive type), which you may well modify inside of the function.
But, to answer your question. Here is a solution:
function populateIfNull(variableName, value){
this[variableName] = this[variableName] || value
}
Which you can use like:
populateIfNull('name', 'Bob')
populateIfNull('age', 20)
AS3 does not have pass by reference (it is similar to Java in this regard, in that it passes references by value).
Something similar can be simulated if you control the client code by wrapping the object in another object:
var myObj = null;
myFun({ a: myObj });
function (param) {
if (param.a == null) {
param.a = "Hello";
}
}
Use objects.
eg:
var myObj : Object = new Object();
var myArr : Array;
myObj.arr = myArr;
function populateViaRef(obj : Object) : void {
obj.arr = new Array();
for(var i : Number = 0; i < 10; i++)
obj.arr[i] = i;
}
populateViaRef(myObj);
for(var i : Number = 0; i < 10; i++)
trace(myObj.arr[i]);
In ActionScript 3.0, all arguments are passed by reference, because all values are stored as objects. However, objects that belong to the primitive data types, which includes Boolean, Number, int, uint, and String, have special operators that make them behave as if they were passed by value.
http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7f56.html
In Java arguments are passed by value.
http://javadude.com/articles/passbyvalue.htm
Data binding in ActionScript is really cool. But what if I want to refactor a big switch or if statement inside the curly braces into a function, for example:
{person.gender == 'male' ? 'Mr.' : 'Ms.'}
into:
{salutation(person)}
The compiler doesn't let me do that. I know about properties and I could write getters and setters on the person object. But since I am using inlined JSON objects now that's not convenient(I think). What are other good ways to refactor this code?
To answer Matt's comment. The data type of person is just plain Object. It was decoded from JSON format coming from a service call.
You'll need to make the Person class (assuming you have one) bindable in order for this to work.
However, since you are saying you're using JSON objects, I'm assuming you just have anonymous objects that were parsed from a JSON string. In that case, I'm pretty sure that won't work. You'll need to create a strongly typed object that has bindable properties.
Just FYI: to avoid having to write custom JSON parsers for every object you want to create, you can create strong typed objects from vanilla objects using a bytearray trick:
public static function toInstance( object:Object, clazz:Class ):* {
var bytes:ByteArray = new ByteArray();
bytes.objectEncoding = ObjectEncoding.AMF0;
// Find the objects and byetArray.writeObject them, adding in the
// class configuration variable name -- essentially, we're constructing
// and AMF packet here that contains the class information so that
// we can simplly byteArray.readObject the sucker for the translation
// Write out the bytes of the original object
var objBytes:ByteArray = new ByteArray();
objBytes.objectEncoding = ObjectEncoding.AMF0;
objBytes.writeObject( object );
// Register all of the classes so they can be decoded via AMF
var typeInfo:XML = describeType( clazz );
var fullyQualifiedName:String = typeInfo.#name.toString().replace( /::/, "." );
registerClassAlias( fullyQualifiedName, clazz );
// Write the new object information starting with the class information
var len:int = fullyQualifiedName.length;
bytes.writeByte( 0x10 ); // 0x10 is AMF0 for "typed object (class instance)"
bytes.writeUTF( fullyQualifiedName );
// After the class name is set up, write the rest of the object
bytes.writeBytes( objBytes, 1 );
// Read in the object with the class property added and return that
bytes.position = 0;
// This generates some ReferenceErrors of the object being passed in
// has properties that aren't in the class instance, and generates TypeErrors
// when property values cannot be converted to correct values (such as false
// being the value, when it needs to be a Date instead). However, these
// errors are not thrown at runtime (and only appear in trace ouput when
// debugging), so a try/catch block isn't necessary. I'm not sure if this
// classifies as a bug or not... but I wanted to explain why if you debug
// you might seem some TypeError or ReferenceError items appear.
var result:* = bytes.readObject();
return result;
}