I am trying to build a dynamic Property Accessor. Want something which is like really fast as close to calling the actually Property. Dont want to go the Reflection route as its very slow. So i opted to using DynamicAssembly and inject IL using ILGenerator. Below is the ILGenerator related code which seems to work
Label nulllabel = getIL.DefineLabel();
Label returnlabel = getIL.DefineLabel();
//_type = targetGetMethod.ReturnType;
if (methods.Count > 0)
{
getIL.DeclareLocal(typeof(object));
getIL.DeclareLocal(typeof(bool));
getIL.Emit(OpCodes.Ldarg_1); //Load the first argument
//(target object)
//Cast to the source type
getIL.Emit(OpCodes.Castclass, this.mTargetType);
//Get the property value
foreach (var methodInfo in methods)
{
getIL.EmitCall(OpCodes.Call, methodInfo, null);
if (methodInfo.ReturnType.IsValueType)
{
getIL.Emit(OpCodes.Box, methodInfo.ReturnType);
//Box if necessary
}
}
getIL.Emit(OpCodes.Stloc_0); //Store it
getIL.Emit(OpCodes.Br_S,returnlabel);
getIL.MarkLabel(nulllabel);
getIL.Emit(OpCodes.Ldnull);
getIL.Emit(OpCodes.Stloc_0);
getIL.MarkLabel(returnlabel);
getIL.Emit(OpCodes.Ldloc_0);
}
else
{
getIL.ThrowException(typeof(MissingMethodException));
}
getIL.Emit(OpCodes.Ret);
So above get the first argument which is the object that contains the property. the methods collection contains the nested property if any. for each property i use EmitCall which puts the the value on the stack and then i try to box it. This works like a charm.
The only issue is if you have a property like Order.Instrument.Symbol.Name and assume that Instrument object is null. Then the code will throw an null object exception.
So this what i did, i introduced a null check
foreach (var methodInfo in methods)
{
getIL.EmitCall(OpCodes.Call, methodInfo, null);
getIL.Emit(OpCodes.Stloc_0);
getIL.Emit(OpCodes.Ldloc_0);
getIL.Emit(OpCodes.Ldnull);
getIL.Emit(OpCodes.Ceq);
getIL.Emit(OpCodes.Stloc_1);
getIL.Emit(OpCodes.Ldloc_1);
getIL.Emit(OpCodes.Brtrue_S, nulllabel);
getIL.Emit(OpCodes.Ldloc_0);
if (methodInfo.ReturnType.IsValueType)
{
getIL.Emit(OpCodes.Box, methodInfo.ReturnType);
//Box if necessary
}
}
Now this code breaks saying That the object/memory is corrupted etc. So what exactly is wrong with this code. Am i missing something here.
Thanks in Advance.
Previously, if you had consecutive properties P returning string and then Q returning int, you would get something like this:
...
call P // returns string
call Q // requires a string on the stack, returns an int
box
...
Now you have something like this:
...
call P // returns string
store // stores to object
... // load, compare to null, etc.
load // loads an *object*
call Q // requires a *string* on the stack
store // stores to object *without boxing*
...
So I see two clear problems:
You are calling methods in such a way that the target is only known to be an object, not a specific type which has that method.
You are not boxing value types before storing them to a local of type object.
These can be solved by reworking your logic slightly. There are also a few other minor details you could clean up:
Rather than ceq followed by brtrue, just use beq.
There's no point in doing Stloc_1 followed by Ldloc_1 rather than just using the value on the stack since that local isn't used anywhere else.
Incorporating these changes, here's what I'd do:
Type finalType = null;
foreach (var methodInfo in methods)
{
finalType = methodInfo.ReturnType;
getIL.EmitCall(OpCodes.Call, methodInfo, null);
if (!finalType.IsValueType)
{
getIL.Emit(OpCodes.Dup);
getIL.Emit(OpCodes.Ldnull);
getIL.Emit(OpCodes.Beq_S, nulllabel);
}
}
if (finalType.IsValueType)
{
getIL.Emit(OpCodes.Box, methodInfo.ReturnType);
//Box if necessary
}
getIL.Emit(OpCodes.Br_S, returnLabel);
getIL.MarkLabel(nulllabel);
getIL.Emit(OpCodes.Pop);
getIL.Emit(OpCodes.Ldnull);
getIL.MarkLabel(returnlabel);
Note that we can get rid of both locals since we now just duplicate the top value on the stack before comparing against null.
Related
I'm having to create my own custom sink because none of the ones currently available give me what I need.
Issue I have is when fetching the key/value pair Value from the logEvent message in the Emit Method, the value is wrapped with quotation marks & backslashes.
I've tried converting the out value from the dictionary into a string and then removing the unwanted attributes but nothing is working for me.
Method in my Custom Sink Class:
public void Emit(LogEvent logEvent)
{
var properties = logEvent.Properties;
Serilog.Events.LogEventPropertyValue value;
if (properties.TryGetValue("logEventCategory", out value))
{
// Regex.Replace((value.ToString() ?? "").Replace("'", #"\'").Trim(), #"[\r\n]+", " "); // Not working
var notWorking = value.ToString();
var formattedValueNotWorking = value.ToString().Replace("\r\n", "\\r\\n");
}
}
It just seems that any attempted formatting of the key/value pair Value is ignored: You see that the example string value System is wrapped with a \"System\"
All I want is the actual string, not the backslashes or quotation marks that is wrapped around the string.
Creating my own sink is a hard enough task and I just want to keep things simple, have spent two days trying to understand the wider picture in message formatting but with custom sinks it gets too complicated and bloated coding for what I need. All the other standard message structure attributes are rendering OK, such as message / level / timestamp etc, it's just fine tuning the rendering of the propertie values I require in order to save these values into their own columns in my DB.
You need to unwrap the string from the enclosing ScalarValue:
// using Serilog.Events;
public void Emit(LogEvent logEvent)
{
var properties = logEvent.Properties;
Serilog.Events.LogEventPropertyValue value;
if (properties.TryGetValue("logEventCategory", out value) &&
value is ScalarValue sv &&
sv.Value is string rawValue)
{
// `rawValue` is what you're looking for
Looks like I just needed to use the correct syntax for string replace:
public void Emit(LogEvent logEvent)
{
var properties = logEvent.Properties;
Serilog.Events.LogEventPropertyValue value;
if (properties.TryGetValue("logEventCategory", out value))
{
var formattedValueWorking = value.ToString().Replace("\"", "");
var test = formattedValueWorking;
}
}
I have refactored a bit my code, so i need a pointer that could contain multiple liste types :
owl_list = new Gee.LinkedList<OpenWithAction> ();
a_list = new Gee.LinkedList<OpenAppAction> ();
Gee.List* any_list = null;
So i have a pointer any_list which i can use to access either owl_list or a_list (depending on a switch no present here, but assume there is)
if (!any_list.size)
return null;
But this will fail as valac throws at me error: The name `size' does not exist in the context of `Gee.List*'
if (!any_list.size)
I haven't done any C,C++ since a very long time and I'm no vala expert, since i use more typeless languages, but is there any way this could work ?
EDIT:
I just tried
fieldType = OpenWithAction.get_type();
if (!(any_list as Gee.List<fieldType>).size)
error: The type name `fieldType' could not be found
if (!(any_list as Gee.List<fieldType>).size)
Obviously I'm doing something wrong, what i'm trying to do is : Vala: determine generic type inside List at runtime, i just can"t manage to implement it.
return null;
EDIT 2:
I just solved partially my problem :
As said by #jens-mühlenhoff, yes OpenWithAction and OpenAppAction have a common ancestor and it is GLib.Action
So all i had to do is declare :
Gee.List<Action> any_list = null;
instead of
Gee.List* any_list = null;
now foreach (var action in any_list) is working, but i'm still getting an error with
if (any_list->size == null)
return null;
error: The name `size' does not exist in the context of `Gee.List<Synapse.Action>?'
if (any_list->size == null)
another try is :
if (!any_list.size)
return null;
Operator not supported for `int'
if (!any_list.size)
any_list is a pointer, so you can't use the . operator. Try any_list->size.
Two things i was doing wrong :
1-
Like in C# i should not have used a pointer if not needed. So using :
Gee.List<Action> any_list = null; is just working fine. The explanation is that OpenWithAction and OpenAppAction have a common ancestor class, So declaring a List with that type is just working fine ( on the other hand i don't know in the case they didn't have a common ancestor).
2- int type can't be used as bool type so if (any_list.size == 0) would work whereas if (!any_list.size) would throw an error
Thanks every one for helping :)
I don't know why i'm having this behavior with my code coverage, maybe someone knows the reasson.
As you may know, code coverage is blue when reached, red when not reached, yellow when partially reached a line of code.
I coded a little mapper that receives a IDataReader and turns into object thanks to reflection.
internal IEnumerable<T> Convert<T>(System.Data.IDataReader dataReader) where T : new()
{
var columns = this.GetColumns(dataReader); // get a list of column name... not important.
var result = new List<T>();
while (dataReader.Read())
{
var nuevoObjeto = new T(); // <-- this line is yellow in code coverage.
foreach (var item in columns)
{
var pi = nuevoObjeto.GetType().GetProperty(item);
pi.SetValue(nuevoObjeto, dataReader[columns.IndexOf(item)]);
}
result.Add(nuevoObjeto);
}
return result;
}
As you can see, the yellow line is not a conditional like IF or WHILE... is just a simple "new T"
And if you debug this code, debug reaches very well that line, in fact test is green with expected results.
Test performs this steps.
Fake IDataReader (with nSubstitute)
Only 1 result on the datareader.
T is tested with only one TestClass... like USERTEST.
hope someone knows why this happens...
thanks!
The IL that gets generated for that line is equivalent to:
T nuevoObjeto = (default(T) == null) ? Activator.CreateInstance<T>() : default(T);
This allows structs to be used for the generic type as they satisfy the new constraint.
So, if you want 100% code coverage, test your generic method with a struct or change the constraint to require that the generic type be a class using where T : class
Try to test it also with struct or add class constraint to the generic method - http://www.codeproject.com/Tips/175592/Code-Coverage-And-Generics
OK I am looping through the properties in an object like so:
private var _propsList:Object = {'Type':'product_type'
,'Kind':'product_type_sub'
,'Stone':'primary_stone'
,'Stone Color':'primary_stone_sub'
,'Metal':'metal_type'
,'Brand':'product_brand'};
for(key in _propsList)
{
val = _propsList[key];
trace(key +" = "+ val);
}
I am expecting the first trace to be Type = property_type since that is the first one defined in the array, however it is coming up random everytime. I guess this is because my keys are strings and not integers, however is there a way to specify the order it loops through them?
Thanks!!
You can't rely on for (v in someObject) ... to return things in a predictable order, no.
Depending on your specific situation, you could just use an array to hold the keys, and just iterate through that:
private var keys:Array = ["Type", "Kind", "Stone", "Stone Color", "Metal", "Brand"];
private function iterate():void
{
for each (var k:String in keys)
{
trace(_propsList[k]);
}
}
Maybe a bit obvious or non-elegant, but it'd get the job done. :)
you could hack it by classing-out your "_propsList" object creating an array inside of the newly created PropsList class that references the properties in order. At that point, you could run a FOR loop on the array and get your properties in order.
OR, you could have a function inside that new class that would return an Array of those properties. like this:
public function getProps():Array {
return [myPropertyOne, myPropertyTwo, myPropertyThree];
}
In general, I think this is a case where you shouldn't depend on a particular behavior from the framework/language you are using. This type of behavior is generally poorly documented and can change from version to version.
If you really need a specific retrieval order, I would create a wrapper class as jevinkones suggested above. Maybe there's even a utility class in the framework somewhere to accomplish this (Dictionary, etc.?)
HTH,
Karthik
I found this link that gives some background:
Subtle Change in for..in Loops for ActionScript 3
This question is actually a dup of this one.
How about using an array representation like this:
var _propsList:Array = [
['Type', 'product_type'],
['Kind', 'product_type_sub'],
['Stone', 'primary_stone'],
['Stone Color', 'primary_stone_sub'],
['Metal', 'metal_type'],
['Brand', 'product_brand']
];
for(var i in _propsList) {
var elem = _propsList[i];
var key = elem[0];
var val = elem[1]
}
I'm modifying the "Edit.aspx" default page template used by ASP.NET Dynamic Data and adding some additional controls. I know that I can find the type of object being edited by looking at DetailsDataSource.GetTable().EntityType, but how can I see the actual object itself? Also, can I change the properties of the object and tell the data context to submit those changes?
Maybe you have found a solution already, however I'd like to share my expresience on this.
It turned out to be a great pita, but I've managed to obtain the editing row. I had to extract the DetailsDataSource WhereParameters and then create a query in runtime.
The code below works for tables with a single primary key. If you have compound keys, I guess, it will require modifications:
Parameter param = null;
foreach(object item in (DetailsDataSource.WhereParameters[0] as DynamicQueryStringParameter).GetWhereParameters(DetailsDataSource)) {
param = (Parameter)item;
break;
}
IQueryable query = DetailsDataSource.GetTable().GetQuery();
ParameterExpression lambdaArgument = Expression.Parameter(query.ElementType, "");
object paramValue = Convert.ChangeType(param.DefaultValue, param.Type);
Expression compareExpr = Expression.Equal(
Expression.Property(lambdaArgument, param.Name),
Expression.Constant(paramValue)
);
Expression lambda = Expression.Lambda(compareExpr, lambdaArgument);
Expression filteredQuery = Expression.Call(typeof(Queryable), "Where", new Type[] { query.ElementType }, query.Expression, lambda);
var WANTED = query.Provider.CreateQuery(filteredQuery).Cast<object>().FirstOrDefault<object>();
If it's a DD object you may be able to use FieldTemplateUserControl.FindFieldTemplate(controlId). Then if you need to you can cast it as an ITextControl to manipulate data.
Otherwise, try using this extension method to find the child control:
public static T FindControl<T>(this Control startingControl, string id) where T : Control
{
T found = startingControl.FindControl(id) as T;
if (found == null)
{
found = FindChildControl<T>(startingControl, id);
}
return found;
}
I found another solution, the other ones did not work.
In my case, I've copied Edit.aspx in /CustomPages/Devices/
Where Devices is the name of the table for which I want this custom behaviour.
Add this in Edit.aspx -> Page_Init()
DetailsDataSource.Selected += entityDataSource_Selected;
Add this in Edit.aspx :
protected void entityDataSource_Selected(object sender, EntityDataSourceSelectedEventArgs e)
{
Device device = e.Results.Cast<Device>().First();
// you have the object/row being edited !
}
Just change Device to your own table name.