locked
Moving existing code to a PCL RRS feed

  • Question

  • User78729 posted

    Hi,

    Below is a piece of code that I've used quite a number of times on droid and iOS without a hitch but for a new project, could do with having it in a PCL. While most of it will work fine, the likes of GetMethod, GetProperties,GetCustomAttributes, IgnoreAttribute and Length aren't available in the PCL version of System.Type.

    Any suggestions on how to move this across? I know I could refactor all of the Get[*] calls to use DI, but I'm guessing that I would need to make the calls to be async to ensure the flow continues correctly which will have a performance hit.

    I've seen the likes of SHA256 brought to PCL by Microsoft (PCLCrypto is on nuget and has a MS shared code licence). Is there a way to do the same but for my example?

    public string GetInsertQuery(Object entity)
            {
                var type = entity.GetType();
                if (!queryBuilders.ContainsKey(type))
                {
                    var param = Expression.Parameter(typeof(Object), "entity");
                    var typedObject = Expression.Variable(type, "obj");
                    var stringBuilder = Expression.Variable(typeof(StringBuilder), "sb");
                    var appendString = typeof(StringBuilder).GetMethod("Append", new[] { typeof(String) });
                    var objectToString = typeof(Object).GetMethod("ToString");
                    var code = new List<Expression>();
                    code.Add(Expression.Assign(typedObject, Expression.Convert(param, type)));
                    code.Add(Expression.Assign(stringBuilder, Expression.New(typeof(StringBuilder)))); 
                    code.Add(Expression.Call(stringBuilder, appendString, Expression.Constant(string.Format("INSERT INTO {0} (", type.Name))));
    
                    var properties = type.GetProperties();
                    for (int i = 0; i < properties.Length - 1; ++i)
                    {
                        if (properties[i].GetCustomAttributes(typeof(IgnoreAttribute), 
                                false).Length > 0)
                            next;
                        code.Add(Expression.Call(stringBuilder, appendString, Expression.Constant(properties[i].Name)));
                        code.Add(Expression.Call(stringBuilder, appendString, Expression.Constant(", ")));
                    }
                    code.Add(Expression.Call(stringBuilder, appendString, Expression.Constant(properties[properties.Length - 1].Name)));
    
                    code.Add(Expression.Call(stringBuilder, appendString, Expression.Constant(") VALUES (")));
    
                    for (int i = 0; i < properties.Length - 1; ++i)
                    {
                        code.Add(Expression.Call(stringBuilder, appendString, Expression.Constant("'")));
                        code.Add(Expression.Call(stringBuilder, appendString, Expression.Call(Expression.Property(typedObject, properties[i]), objectToString)));
                        code.Add(Expression.Call(stringBuilder, appendString, Expression.Constant("', ")));
                    }
    
                    code.Add(Expression.Call(stringBuilder, appendString, Expression.Constant("'")));
                    code.Add(Expression.Call(stringBuilder, appendString, Expression.Call(Expression.Property(typedObject, properties[properties.Length - 1]), objectToString)));
                    code.Add(Expression.Call(stringBuilder, appendString, Expression.Constant("', ")));
    
                    code.Add(Expression.Call(stringBuilder, appendString, Expression.Constant(");")));
    
                    code.Add(Expression.Call(stringBuilder, "ToString", new Type[] { }));
    
                    var expression = Expression.Lambda<Func<Object, String>>(Expression.Block(new[] { typedObject, stringBuilder }, code), param);
                    queryBuilders[type] = expression.Compile();
                }
    
                string f = queryBuilders[type](entity);
                return f;
            }
    

    Thanks

    Paul

    Saturday, January 24, 2015 9:46 AM

Answers

  • User68536 posted

    Hi @Paul-F-Johnson?,

    Just a question, does the Expression.Compile actually work on an iOS device?
    I don't thing this is supported as the AOT compiler currently can't support this.

    Another thing, you seem to be using SQLite, have you tried the sqlite-net-pcl NuGet?
    http://www.nuget.org/packages/sqlite-net-pcl/
    For a few more SQLite ideas: http://forums.xamarin.com/discussion/comment/99677/#Comment_99677

    Finally, you can do this code without Expressions.
    I no longer use the type.GetProperties, but rather type.GetTypeInfo().DeclaredProperties:

    public string GetInsertQuery(Object entity)
    {
        var type = entity.GetType();
        if (!queryBuilders.ContainsKey(type))
        {
            Func<object, string> func = (param) => {
                var paramType = param.GetType ();
    
                var sb = new StringBuilder ();
                sb.Append (string.Format ("INSERT INTO {0} (", type.Name));
    
                var properties = type.GetTypeInfo ().DeclaredProperties.ToArray ();
                for (int i = 0; i < properties.Length; i++) {
                    if (!properties [i].GetCustomAttributes (typeof(IgnoreAttribute), false).Any ()) {
                        sb.Append (properties [i].Name);
                        sb.Append (", ");
                    }
                }
                sb.Append (properties [properties.Length - 1].Name);
                sb.Append (") VALUES (");
    
                for (int i = 0; i < properties.Length - 1; ++i) {
                    sb.Append ("'");
                    sb.Append (properties [i].GetValue (param).ToString ());
                    sb.Append ("', ");
                }
    
                sb.Append ("'");
                sb.Append (properties[properties.Length - 1].GetValue (param).ToString ());
                sb.Append ("');");
    
                return sb.ToString ();
            };
    
            queryBuilders[type] = func;
        }
    
        string f = queryBuilders[type](entity);
        return f;
    }
    
    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Tuesday, January 27, 2015 3:53 PM

All replies

  • User68536 posted

    Hi @Paul-F-Johnson?,

    Just a question, does the Expression.Compile actually work on an iOS device?
    I don't thing this is supported as the AOT compiler currently can't support this.

    Another thing, you seem to be using SQLite, have you tried the sqlite-net-pcl NuGet?
    http://www.nuget.org/packages/sqlite-net-pcl/
    For a few more SQLite ideas: http://forums.xamarin.com/discussion/comment/99677/#Comment_99677

    Finally, you can do this code without Expressions.
    I no longer use the type.GetProperties, but rather type.GetTypeInfo().DeclaredProperties:

    public string GetInsertQuery(Object entity)
    {
        var type = entity.GetType();
        if (!queryBuilders.ContainsKey(type))
        {
            Func<object, string> func = (param) => {
                var paramType = param.GetType ();
    
                var sb = new StringBuilder ();
                sb.Append (string.Format ("INSERT INTO {0} (", type.Name));
    
                var properties = type.GetTypeInfo ().DeclaredProperties.ToArray ();
                for (int i = 0; i < properties.Length; i++) {
                    if (!properties [i].GetCustomAttributes (typeof(IgnoreAttribute), false).Any ()) {
                        sb.Append (properties [i].Name);
                        sb.Append (", ");
                    }
                }
                sb.Append (properties [properties.Length - 1].Name);
                sb.Append (") VALUES (");
    
                for (int i = 0; i < properties.Length - 1; ++i) {
                    sb.Append ("'");
                    sb.Append (properties [i].GetValue (param).ToString ());
                    sb.Append ("', ");
                }
    
                sb.Append ("'");
                sb.Append (properties[properties.Length - 1].GetValue (param).ToString ());
                sb.Append ("');");
    
                return sb.ToString ();
            };
    
            queryBuilders[type] = func;
        }
    
        string f = queryBuilders[type](entity);
        return f;
    }
    
    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Tuesday, January 27, 2015 3:53 PM
  • User78729 posted

    That's cool - thanks and yes, I do use the async version of sqllite :)

    Monday, February 9, 2015 4:17 PM