Sickboy
2011-Jun-14  15:38 UTC
[Ironruby-core] WPF Databinding with RubyObjects, continuation, dynamically create wrappers with strong typed properties
Hello,
I recently stumbled upon this awesome code:
http://rubyforge.org/pipermail/ironruby-core/2008-December/003377.html
It does exactly what I need; dynamically wrapping my RubyObject into a CLR class
with CLR properties, except that it?s designed only for string properties.
I?ve adjusted the code to support a number of types, incl int, bool and float.
However the CLR crashes when-ever I assign a value to a non-string property, e.g
float or int.
?The runtime has encountered a fatal error. The address of the error was at
0x5935788d, on thread 0x1adc. The error code is 0xc0000005. This error may be a
bug in the CLR or in the unsafe or non-verifiable portions of user code. Common
sources of this bug include user marshaling errors for COM-interop or PInvoke,
which may corrupt the stack.?
Any assistance would be deeply appreciated.
In essence, instead of using typeof(string) inside the TypeGenerator.Generate
method, i use e.g; typeof(int) or typeof(float)
This is my current code:
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
namespace GenerateType
{
    public class TypeGenerator
    {
        public delegate object GetPropertyDelegate(string propertyName);
        public delegate object SetPropertyDelegate(string propertyName, object
value);
        public static Type Generate(string className, Dictionary<string,
List<string>> properties)
        {
            AssemblyName asmName = new AssemblyName("BindingTypes");
            AssemblyBuilder asmBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(asmName,
AssemblyBuilderAccess.Run);
            ModuleBuilder modBuilder =
asmBuilder.DefineDynamicModule("Types");
            TypeBuilder typeBuilder = modBuilder.DefineType(className,
                        TypeAttributes.Public |
                        TypeAttributes.Class |
                        TypeAttributes.AutoClass |
                        TypeAttributes.AnsiClass |
                        TypeAttributes.BeforeFieldInit |
                        TypeAttributes.AutoLayout);
            FieldBuilder getFieldBuilder =
typeBuilder.DefineField("OnGet", typeof(GetPropertyDelegate),
FieldAttributes.Public);
            FieldBuilder setFieldBuilder =
typeBuilder.DefineField("OnSet", typeof(SetPropertyDelegate),
FieldAttributes.Public);
            MethodAttributes getSetAttr = MethodAttributes.Public |
MethodAttributes.SpecialName | MethodAttributes.HideBySig;
            Type type = null;
            foreach (string s in properties.Keys)
            {
                type = null;
                switch (s)
                {
                    case "float":
                        type = typeof(float);
                        break;
                    case "int":
                        type = typeof(int);
                        break;
                    case "string":
                        type = typeof(string);
                        break;
                    case "bool":
                        type = typeof(bool);
                        break;
                    //case "dynamic":
                    //    type = dynamic;
                }
                if (type != null)
                {
                    GenerateProperties(properties[s], type, typeBuilder,
getSetAttr, getFieldBuilder, setFieldBuilder);
                }
            }
            return typeBuilder.CreateType();
        }
        public static void GenerateProperties(List<string> properties,
Type type, TypeBuilder typeBuilder, MethodAttributes getSetAttr, FieldBuilder
getFieldBuilder, FieldBuilder setFieldBuilder)
        {
            foreach (string propertyName in properties)
            {
                PropertyBuilder propBuilder =
typeBuilder.DefineProperty(propertyName, PropertyAttributes.None,
typeof(object), new Type[] {});
                MethodBuilder getter = typeBuilder.DefineMethod("get_"
+ propertyName,
                                   getSetAttr,
                                   type,
                                   Type.EmptyTypes);
                ILGenerator ilGen = getter.GetILGenerator();
                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Ldfld, getFieldBuilder);
                ilGen.Emit(OpCodes.Ldstr, propertyName);
                ilGen.Emit(OpCodes.Callvirt,
typeof(GetPropertyDelegate).GetMethod("Invoke"));
                ilGen.Emit(OpCodes.Ret);
                // Define the "set" accessor method for CustomerName.
                MethodBuilder setter = typeBuilder.DefineMethod("set_"
+ propertyName,
                                               getSetAttr,
                                               null,
                                               new Type[] { type });
                ilGen = setter.GetILGenerator();
                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Ldfld, setFieldBuilder);
                ilGen.Emit(OpCodes.Ldstr, propertyName);
                ilGen.Emit(OpCodes.Ldarg_1);
                ilGen.Emit(OpCodes.Callvirt,
typeof(SetPropertyDelegate).GetMethod("Invoke"));
                ilGen.Emit(OpCodes.Pop);
                ilGen.Emit(OpCodes.Ret);
                // Last, we must map the two methods created above to our
PropertyBuilder to
                // their corresponding behaviors, "get" and
"set" respectively.
                propBuilder.SetGetMethod(getter);
                propBuilder.SetSetMethod(setter);
            }
        }
    }
}
Ruby Code:
include System::Data
include System::Windows::Data
include System::ComponentModel
include GenerateType 
class WrapperGenerator
  def initialize
    @wrapper_cache = {}
  end
  def wrap(ruby_object)
    if ruby_object.is_a? Array
      ruby_object.map {|o| wrap(o) }
    else
      cache(ruby_object) unless cached(ruby_object)
      wrapper_class = cached(ruby_object)
      wrapper_class.new(ruby_object)
    end
  end
  def invalidate
    @wrapper_cache.clear
  end
private
  def cached(object)
    @wrapper_cache[object.class.name]
  end
  def cache(object)
    @wrapper_cache[object.class.name] = generate_wrapper(object)
  end
  def generate_wrapper(object)
    wrapper_name = "#{object.class.name}Wrapper"
    properties = Dictionary.of(System::String, List.of(System::String)).new
    if defined?(object.class::PROPERTY_DESCRIPTORS)
      object.class::PROPERTY_DESCRIPTORS.each_pair do |k, v|
        properties[k.to_clr_string] = List.of(System::String).new
        properties[k.to_clr_string].replace v.map{|e| e.to_clr_string}
      end
    else
      # Default to String properties
      properties["string"] = List.of(System::String).new
      properties["string"].replace (object.methods -
Object.instance_methods).map{|e| e.to_clr_string}
    end
    wrapper_base_type = TypeGenerator.generate("#{wrapper_name}Base",
properties)
    base_instance = System::Activator.create_instance wrapper_base_type
    eval <<EOS
      class #{wrapper_name} < base_instance.class
        def initialize(original)
          self.on_get = lambda do |prop|
            original.send prop
          end
          self.on_set = lambda do |prop, val|
            original.send "\#{prop}=", val
          end
        end
      end
      return #{wrapper_name} # return the class
EOS
  end
end
class Person
  attr_accessor :test
  PROPERTY_DESCRIPTORS = { :int => [:test] }
end
wrapper = WrapperGenerator.new
wrapped = wrapper.wrap(Person.new)
puts "Wrapped"
# wrapped.test = "35" # properly generates Exception: Cannot convert
String to Fixnum
wrapped.test = 35 # !!!!! Crashes here !!!!!
puts "Assigned"
puts wrapped.test, wrapped.test.inspect, wrapped.test.class
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://rubyforge.org/pipermail/ironruby-core/attachments/20110614/6fd546e8/attachment-0001.html>
Tomas Matousek
2011-Jun-14  16:05 UTC
[Ironruby-core] WPF Databinding with RubyObjects, continuation, dynamically create wrappers with strong typed properties
My guess would be that you?re not boxing the value.
You need to emit OpCodes.Box to convert bool/int/? to an Object before calling
Invoke in setter. The setter should also return Object (your?s is void). In
getter you need to use OpCodes.Unbox before returning.
I?d also recommend using Func<> delegate instead of your custom delegate
types if possible.
Tomas
From: ironruby-core-bounces at rubyforge.org [mailto:ironruby-core-bounces at
rubyforge.org] On Behalf Of Sickboy
Sent: Tuesday, June 14, 2011 8:38 AM
To: ironruby-core at rubyforge.org
Subject: [Ironruby-core] WPF Databinding with RubyObjects, continuation,
dynamically create wrappers with strong typed properties
Hello,
I recently stumbled upon this awesome code:
http://rubyforge.org/pipermail/ironruby-core/2008-December/003377.html
It does exactly what I need; dynamically wrapping my RubyObject into a CLR class
with CLR properties, except that it?s designed only for string properties.
I?ve adjusted the code to support a number of types, incl int, bool and float.
However the CLR crashes when-ever I assign a value to a non-string property, e.g
float or int.
?The runtime has encountered a fatal error. The address of the error was at
0x5935788d, on thread 0x1adc. The error code is 0xc0000005. This error may be a
bug in the CLR or in the unsafe or non-verifiable portions of user code. Common
sources of this bug include user marshaling errors for COM-interop or PInvoke,
which may corrupt the stack.?
Any assistance would be deeply appreciated.
In essence, instead of using typeof(string) inside the TypeGenerator.Generate
method, i use e.g; typeof(int) or typeof(float)
This is my current code:
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
namespace GenerateType
{
    public class TypeGenerator
    {
        public delegate object GetPropertyDelegate(string propertyName);
        public delegate object SetPropertyDelegate(string propertyName, object
value);
        public static Type Generate(string className, Dictionary<string,
List<string>> properties)
        {
            AssemblyName asmName = new AssemblyName("BindingTypes");
            AssemblyBuilder asmBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(asmName,
AssemblyBuilderAccess.Run);
            ModuleBuilder modBuilder =
asmBuilder.DefineDynamicModule("Types");
            TypeBuilder typeBuilder = modBuilder.DefineType(className,
                        TypeAttributes.Public |
                        TypeAttributes.Class |
                        TypeAttributes.AutoClass |
                        TypeAttributes.AnsiClass |
                        TypeAttributes.BeforeFieldInit |
                        TypeAttributes.AutoLayout);
            FieldBuilder getFieldBuilder =
typeBuilder.DefineField("OnGet", typeof(GetPropertyDelegate),
FieldAttributes.Public);
            FieldBuilder setFieldBuilder =
typeBuilder.DefineField("OnSet", typeof(SetPropertyDelegate),
FieldAttributes.Public);
            MethodAttributes getSetAttr = MethodAttributes.Public |
MethodAttributes.SpecialName | MethodAttributes.HideBySig;
            Type type = null;
            foreach (string s in properties.Keys)
            {
                type = null;
                switch (s)
                {
                    case "float":
                        type = typeof(float);
                        break;
                    case "int":
                        type = typeof(int);
                        break;
                    case "string":
                        type = typeof(string);
                        break;
                    case "bool":
                        type = typeof(bool);
                        break;
                    //case "dynamic":
                    //    type = dynamic;
                }
                if (type != null)
                {
                    GenerateProperties(properties[s], type, typeBuilder,
getSetAttr, getFieldBuilder, setFieldBuilder);
                }
            }
            return typeBuilder.CreateType();
        }
        public static void GenerateProperties(List<string> properties,
Type type, TypeBuilder typeBuilder, MethodAttributes getSetAttr, FieldBuilder
getFieldBuilder, FieldBuilder setFieldBuilder)
        {
            foreach (string propertyName in properties)
            {
                PropertyBuilder propBuilder =
typeBuilder.DefineProperty(propertyName, PropertyAttributes.None,
typeof(object), new Type[] {});
                MethodBuilder getter = typeBuilder.DefineMethod("get_"
+ propertyName,
                                   getSetAttr,
                                   type,
                                   Type.EmptyTypes);
                ILGenerator ilGen = getter.GetILGenerator();
                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Ldfld, getFieldBuilder);
                ilGen.Emit(OpCodes.Ldstr, propertyName);
                ilGen.Emit(OpCodes.Callvirt,
typeof(GetPropertyDelegate).GetMethod("Invoke"));
                ilGen.Emit(OpCodes.Ret);
                // Define the "set" accessor method for CustomerName.
                MethodBuilder setter = typeBuilder.DefineMethod("set_"
+ propertyName,
                                               getSetAttr,
                                               null,
                                               new Type[] { type });
                ilGen = setter.GetILGenerator();
                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Ldfld, setFieldBuilder);
                ilGen.Emit(OpCodes.Ldstr, propertyName);
                ilGen.Emit(OpCodes.Ldarg_1);
                ilGen.Emit(OpCodes.Callvirt,
typeof(SetPropertyDelegate).GetMethod("Invoke"));
                ilGen.Emit(OpCodes.Pop);
                ilGen.Emit(OpCodes.Ret);
                // Last, we must map the two methods created above to our
PropertyBuilder to
                // their corresponding behaviors, "get" and
"set" respectively.
                propBuilder.SetGetMethod(getter);
                propBuilder.SetSetMethod(setter);
            }
        }
    }
}
Ruby Code:
include System::Data
include System::Windows::Data
include System::ComponentModel
include GenerateType
class WrapperGenerator
  def initialize
    @wrapper_cache = {}
  end
  def wrap(ruby_object)
    if ruby_object.is_a? Array
      ruby_object.map {|o| wrap(o) }
    else
      cache(ruby_object) unless cached(ruby_object)
      wrapper_class = cached(ruby_object)
      wrapper_class.new(ruby_object)
    end
  end
  def invalidate
    @wrapper_cache.clear
  end
private
  def cached(object)
    @wrapper_cache[object.class.name]
  end
  def cache(object)
    @wrapper_cache[object.class.name] = generate_wrapper(object)
  end
  def generate_wrapper(object)
    wrapper_name = "#{object.class.name}Wrapper"
    properties = Dictionary.of(System::String, List.of(System::String)).new
    if defined?(object.class::PROPERTY_DESCRIPTORS)
      object.class::PROPERTY_DESCRIPTORS.each_pair do |k, v|
        properties[k.to_clr_string] = List.of(System::String).new
        properties[k.to_clr_string].replace v.map{|e| e.to_clr_string}
      end
    else
      # Default to String properties
      properties["string"] = List.of(System::String).new
      properties["string"].replace (object.methods -
Object.instance_methods).map{|e| e.to_clr_string}
    end
    wrapper_base_type = TypeGenerator.generate("#{wrapper_name}Base",
properties)
    base_instance = System::Activator.create_instance wrapper_base_type
    eval <<EOS
      class #{wrapper_name} < base_instance.class
        def initialize(original)
          self.on_get = lambda do |prop|
            original.send prop
          end
          self.on_set = lambda do |prop, val|
            original.send "\#{prop}=", val
          end
        end
      end
      return #{wrapper_name} # return the class
EOS
  end
end
class Person
  attr_accessor :test
  PROPERTY_DESCRIPTORS = { :int => [:test] }
end
wrapper = WrapperGenerator.new
wrapped = wrapper.wrap(Person.new)
puts "Wrapped"
# wrapped.test = "35" # properly generates Exception: Cannot convert
String to Fixnum
wrapped.test = 35 # !!!!! Crashes here !!!!!
puts "Assigned"
puts wrapped.test, wrapped.test.inspect, wrapped.test.class
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://rubyforge.org/pipermail/ironruby-core/attachments/20110614/0b1f497b/attachment-0001.html>
Sickboy
2011-Jun-14  17:03 UTC
[Ironruby-core] WPF Databinding with RubyObjects, continuation, dynamically create wrappers with strong typed properties
Thanks! Still new to .NET and especially this stuff.
The Box/Unbox seems to have worked, except that if I set e.g 35 as new value,
when reading the value back, something completely different comes back, e.g;
150007660, but correct class Fixnum.
This number seems randomized, and changes upon accessing the getter for the
property more than once.
Any suggestions or alternatives welcome.
My backup plan is to generate the C# classes from Ruby dynamically during
development and saving them into a .cs file to be compiled with exe/dll.
Regards
From: Tomas Matousek 
Sent: Tuesday, June 14, 2011 6:05 PM
To: ironruby-core at rubyforge.org 
Subject: Re: [Ironruby-core] WPF Databinding with RubyObjects,
continuation,dynamically create wrappers with strong typed properties
My guess would be that you?re not boxing the value.
You need to emit OpCodes.Box to convert bool/int/? to an Object before calling
Invoke in setter. The setter should also return Object (your?s is void). In
getter you need to use OpCodes.Unbox before returning.
I?d also recommend using Func<> delegate instead of your custom delegate
types if possible.
 
Tomas
 
From: ironruby-core-bounces at rubyforge.org [mailto:ironruby-core-bounces at
rubyforge.org] On Behalf Of Sickboy
Sent: Tuesday, June 14, 2011 8:38 AM
To: ironruby-core at rubyforge.org
Subject: [Ironruby-core] WPF Databinding with RubyObjects, continuation,
dynamically create wrappers with strong typed properties
 
Hello,
 
I recently stumbled upon this awesome code:
http://rubyforge.org/pipermail/ironruby-core/2008-December/003377.html
It does exactly what I need; dynamically wrapping my RubyObject into a CLR class
with CLR properties, except that it?s designed only for string properties.
 
I?ve adjusted the code to support a number of types, incl int, bool and float.
 
However the CLR crashes when-ever I assign a value to a non-string property, e.g
float or int.
?The runtime has encountered a fatal error. The address of the error was at
0x5935788d, on thread 0x1adc. The error code is 0xc0000005. This error may be a
bug in the CLR or in the unsafe or non-verifiable portions of user code. Common
sources of this bug include user marshaling errors for COM-interop or PInvoke,
which may corrupt the stack.?
 
Any assistance would be deeply appreciated.
 
In essence, instead of using typeof(string) inside the TypeGenerator.Generate
method, i use e.g; typeof(int) or typeof(float)
This is my current code:
 
C#:
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
 
namespace GenerateType
{
    public class TypeGenerator
    {
        public delegate object GetPropertyDelegate(string propertyName);
        public delegate object SetPropertyDelegate(string propertyName, object
value);
 
        public static Type Generate(string className, Dictionary<string,
List<string>> properties)
        {
            AssemblyName asmName = new AssemblyName("BindingTypes");
            AssemblyBuilder asmBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(asmName,
AssemblyBuilderAccess.Run);
            ModuleBuilder modBuilder =
asmBuilder.DefineDynamicModule("Types");
            TypeBuilder typeBuilder = modBuilder.DefineType(className,
                        TypeAttributes.Public |
                        TypeAttributes.Class |
                        TypeAttributes.AutoClass |
                        TypeAttributes.AnsiClass |
                        TypeAttributes.BeforeFieldInit |
                        TypeAttributes.AutoLayout);
 
 
            FieldBuilder getFieldBuilder =
typeBuilder.DefineField("OnGet", typeof(GetPropertyDelegate),
FieldAttributes.Public);
            FieldBuilder setFieldBuilder =
typeBuilder.DefineField("OnSet", typeof(SetPropertyDelegate),
FieldAttributes.Public);
 
            MethodAttributes getSetAttr = MethodAttributes.Public |
MethodAttributes.SpecialName | MethodAttributes.HideBySig;
 
            Type type = null;
 
            foreach (string s in properties.Keys)
            {
                type = null;
                switch (s)
                {
                    case "float":
                        type = typeof(float);
                        break;
                    case "int":
                        type = typeof(int);
                        break;
                    case "string":
                        type = typeof(string);
                        break;
                    case "bool":
                        type = typeof(bool);
                        break;
                    //case "dynamic":
                    //    type = dynamic;
                }
                if (type != null)
                {
                    GenerateProperties(properties[s], type, typeBuilder,
getSetAttr, getFieldBuilder, setFieldBuilder);
                }
            }
            return typeBuilder.CreateType();
        }
 
        public static void GenerateProperties(List<string> properties,
Type type, TypeBuilder typeBuilder, MethodAttributes getSetAttr, FieldBuilder
getFieldBuilder, FieldBuilder setFieldBuilder)
        {
            foreach (string propertyName in properties)
            {
                PropertyBuilder propBuilder =
typeBuilder.DefineProperty(propertyName, PropertyAttributes.None,
typeof(object), new Type[] {});
                MethodBuilder getter = typeBuilder.DefineMethod("get_"
+ propertyName,
                                   getSetAttr,
                                   type,
                                   Type.EmptyTypes);
 
                ILGenerator ilGen = getter.GetILGenerator();
 
                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Ldfld, getFieldBuilder);
                ilGen.Emit(OpCodes.Ldstr, propertyName);
                ilGen.Emit(OpCodes.Callvirt,
typeof(GetPropertyDelegate).GetMethod("Invoke"));
                ilGen.Emit(OpCodes.Ret);
 
                // Define the "set" accessor method for CustomerName.
                MethodBuilder setter = typeBuilder.DefineMethod("set_"
+ propertyName,
                                               getSetAttr,
                                               null,
                                               new Type[] { type });
 
                ilGen = setter.GetILGenerator();
 
                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Ldfld, setFieldBuilder);
                ilGen.Emit(OpCodes.Ldstr, propertyName);
                ilGen.Emit(OpCodes.Ldarg_1);
                ilGen.Emit(OpCodes.Callvirt,
typeof(SetPropertyDelegate).GetMethod("Invoke"));
                ilGen.Emit(OpCodes.Pop);
                ilGen.Emit(OpCodes.Ret);
 
                // Last, we must map the two methods created above to our
PropertyBuilder to
                // their corresponding behaviors, "get" and
"set" respectively.
                propBuilder.SetGetMethod(getter);
                propBuilder.SetSetMethod(setter);
            }
        }
    }
}
 
 
 
 
Ruby Code:
 
include System::Data
include System::Windows::Data
include System::ComponentModel
 
include GenerateType 
class WrapperGenerator
  def initialize
    @wrapper_cache = {}
  end
 
  def wrap(ruby_object)
    if ruby_object.is_a? Array
      ruby_object.map {|o| wrap(o) }
    else
      cache(ruby_object) unless cached(ruby_object)
      wrapper_class = cached(ruby_object)
      wrapper_class.new(ruby_object)
    end
  end
 
  def invalidate
    @wrapper_cache.clear
  end
private
  def cached(object)
    @wrapper_cache[object.class.name]
  end
 
  def cache(object)
    @wrapper_cache[object.class.name] = generate_wrapper(object)
  end
 
  def generate_wrapper(object)
    wrapper_name = "#{object.class.name}Wrapper"
    properties = Dictionary.of(System::String, List.of(System::String)).new
 
    if defined?(object.class::PROPERTY_DESCRIPTORS)
      object.class::PROPERTY_DESCRIPTORS.each_pair do |k, v|
        properties[k.to_clr_string] = List.of(System::String).new
        properties[k.to_clr_string].replace v.map{|e| e.to_clr_string}
      end
    else
      # Default to String properties
      properties["string"] = List.of(System::String).new
      properties["string"].replace (object.methods -
Object.instance_methods).map{|e| e.to_clr_string}
    end
 
    wrapper_base_type = TypeGenerator.generate("#{wrapper_name}Base",
properties)
    base_instance = System::Activator.create_instance wrapper_base_type
 
    eval <<EOS
      class #{wrapper_name} < base_instance.class
        def initialize(original)
          self.on_get = lambda do |prop|
            original.send prop
          end
 
          self.on_set = lambda do |prop, val|
            original.send "\#{prop}=", val
          end
        end
      end
      return #{wrapper_name} # return the class
EOS
  end
end
 
class Person
  attr_accessor :test
  PROPERTY_DESCRIPTORS = { :int => [:test] }
end
 
wrapper = WrapperGenerator.new
wrapped = wrapper.wrap(Person.new)
puts "Wrapped"
# wrapped.test = "35" # properly generates Exception: Cannot convert
String to Fixnum
wrapped.test = 35 # !!!!! Crashes here !!!!!
puts "Assigned"
puts wrapped.test, wrapped.test.inspect, wrapped.test.class
--------------------------------------------------------------------------------
_______________________________________________
Ironruby-core mailing list
Ironruby-core at rubyforge.org
http://rubyforge.org/mailman/listinfo/ironruby-core
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://rubyforge.org/pipermail/ironruby-core/attachments/20110614/09472f63/attachment-0001.html>
Tomas Matousek
2011-Jun-14  17:49 UTC
[Ironruby-core] WPF Databinding with RubyObjects, continuation, dynamically create wrappers with strong typed properties
Your backup plan might actually be better ? emitting code at runtime is
definitely slower than loading already compiled code.
You?re still emitting some wrong instructions. Can you send your new code?
Tomas
From: ironruby-core-bounces at rubyforge.org [mailto:ironruby-core-bounces at
rubyforge.org] On Behalf Of Sickboy
Sent: Tuesday, June 14, 2011 10:03 AM
To: ironruby-core at rubyforge.org
Subject: Re: [Ironruby-core] WPF Databinding with RubyObjects, continuation,
dynamically create wrappers with strong typed properties
Thanks! Still new to .NET and especially this stuff.
The Box/Unbox seems to have worked, except that if I set e.g 35 as new value,
when reading the value back, something completely different comes back, e.g;
150007660, but correct class Fixnum.
This number seems randomized, and changes upon accessing the getter for the
property more than once.
Any suggestions or alternatives welcome.
My backup plan is to generate the C# classes from Ruby dynamically during
development and saving them into a .cs file to be compiled with exe/dll.
Regards
From: Tomas Matousek<mailto:Tomas.Matousek at microsoft.com>
Sent: Tuesday, June 14, 2011 6:05 PM
To: ironruby-core at rubyforge.org<mailto:ironruby-core at rubyforge.org>
Subject: Re: [Ironruby-core] WPF Databinding with RubyObjects,
continuation,dynamically create wrappers with strong typed properties
My guess would be that you?re not boxing the value.
You need to emit OpCodes.Box to convert bool/int/? to an Object before calling
Invoke in setter. The setter should also return Object (your?s is void). In
getter you need to use OpCodes.Unbox before returning.
I?d also recommend using Func<> delegate instead of your custom delegate
types if possible.
Tomas
From: ironruby-core-bounces at rubyforge.org [mailto:ironruby-core-bounces at
rubyforge.org] On Behalf Of Sickboy
Sent: Tuesday, June 14, 2011 8:38 AM
To: ironruby-core at rubyforge.org
Subject: [Ironruby-core] WPF Databinding with RubyObjects, continuation,
dynamically create wrappers with strong typed properties
Hello,
I recently stumbled upon this awesome code:
http://rubyforge.org/pipermail/ironruby-core/2008-December/003377.html
It does exactly what I need; dynamically wrapping my RubyObject into a CLR class
with CLR properties, except that it?s designed only for string properties.
I?ve adjusted the code to support a number of types, incl int, bool and float.
However the CLR crashes when-ever I assign a value to a non-string property, e.g
float or int.
?The runtime has encountered a fatal error. The address of the error was at
0x5935788d, on thread 0x1adc. The error code is 0xc0000005. This error may be a
bug in the CLR or in the unsafe or non-verifiable portions of user code. Common
sources of this bug include user marshaling errors for COM-interop or PInvoke,
which may corrupt the stack.?
Any assistance would be deeply appreciated.
In essence, instead of using typeof(string) inside the TypeGenerator.Generate
method, i use e.g; typeof(int) or typeof(float)
This is my current code:
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
namespace GenerateType
{
    public class TypeGenerator
    {
        public delegate object GetPropertyDelegate(string propertyName);
        public delegate object SetPropertyDelegate(string propertyName, object
value);
        public static Type Generate(string className, Dictionary<string,
List<string>> properties)
        {
            AssemblyName asmName = new AssemblyName("BindingTypes");
            AssemblyBuilder asmBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(asmName,
AssemblyBuilderAccess.Run);
            ModuleBuilder modBuilder =
asmBuilder.DefineDynamicModule("Types");
            TypeBuilder typeBuilder = modBuilder.DefineType(className,
                        TypeAttributes.Public |
                        TypeAttributes.Class |
                        TypeAttributes.AutoClass |
                        TypeAttributes.AnsiClass |
                        TypeAttributes.BeforeFieldInit |
                        TypeAttributes.AutoLayout);
            FieldBuilder getFieldBuilder =
typeBuilder.DefineField("OnGet", typeof(GetPropertyDelegate),
FieldAttributes.Public);
            FieldBuilder setFieldBuilder =
typeBuilder.DefineField("OnSet", typeof(SetPropertyDelegate),
FieldAttributes.Public);
            MethodAttributes getSetAttr = MethodAttributes.Public |
MethodAttributes.SpecialName | MethodAttributes.HideBySig;
            Type type = null;
            foreach (string s in properties.Keys)
            {
                type = null;
                switch (s)
                {
                    case "float":
                        type = typeof(float);
                        break;
                    case "int":
                        type = typeof(int);
                        break;
                    case "string":
                        type = typeof(string);
                        break;
                    case "bool":
                        type = typeof(bool);
                        break;
                    //case "dynamic":
                    //    type = dynamic;
                }
                if (type != null)
                {
                    GenerateProperties(properties[s], type, typeBuilder,
getSetAttr, getFieldBuilder, setFieldBuilder);
                }
            }
            return typeBuilder.CreateType();
        }
        public static void GenerateProperties(List<string> properties,
Type type, TypeBuilder typeBuilder, MethodAttributes getSetAttr, FieldBuilder
getFieldBuilder, FieldBuilder setFieldBuilder)
        {
            foreach (string propertyName in properties)
            {
                PropertyBuilder propBuilder =
typeBuilder.DefineProperty(propertyName, PropertyAttributes.None,
typeof(object), new Type[] {});
                MethodBuilder getter = typeBuilder.DefineMethod("get_"
+ propertyName,
                                   getSetAttr,
                                   type,
                                   Type.EmptyTypes);
                ILGenerator ilGen = getter.GetILGenerator();
                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Ldfld, getFieldBuilder);
                ilGen.Emit(OpCodes.Ldstr, propertyName);
                ilGen.Emit(OpCodes.Callvirt,
typeof(GetPropertyDelegate).GetMethod("Invoke"));
                ilGen.Emit(OpCodes.Ret);
                // Define the "set" accessor method for CustomerName.
                MethodBuilder setter = typeBuilder.DefineMethod("set_"
+ propertyName,
                                               getSetAttr,
                                               null,
                                               new Type[] { type });
                ilGen = setter.GetILGenerator();
                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Ldfld, setFieldBuilder);
                ilGen.Emit(OpCodes.Ldstr, propertyName);
                ilGen.Emit(OpCodes.Ldarg_1);
                ilGen.Emit(OpCodes.Callvirt,
typeof(SetPropertyDelegate).GetMethod("Invoke"));
                ilGen.Emit(OpCodes.Pop);
                ilGen.Emit(OpCodes.Ret);
                // Last, we must map the two methods created above to our
PropertyBuilder to
                // their corresponding behaviors, "get" and
"set" respectively.
                propBuilder.SetGetMethod(getter);
                propBuilder.SetSetMethod(setter);
            }
        }
    }
}
Ruby Code:
include System::Data
include System::Windows::Data
include System::ComponentModel
include GenerateType
class WrapperGenerator
  def initialize
    @wrapper_cache = {}
  end
  def wrap(ruby_object)
    if ruby_object.is_a? Array
      ruby_object.map {|o| wrap(o) }
    else
      cache(ruby_object) unless cached(ruby_object)
      wrapper_class = cached(ruby_object)
      wrapper_class.new(ruby_object)
    end
  end
  def invalidate
    @wrapper_cache.clear
  end
private
  def cached(object)
    @wrapper_cache[object.class.name]
  end
  def cache(object)
    @wrapper_cache[object.class.name] = generate_wrapper(object)
  end
  def generate_wrapper(object)
    wrapper_name = "#{object.class.name}Wrapper"
    properties = Dictionary.of(System::String, List.of(System::String)).new
    if defined?(object.class::PROPERTY_DESCRIPTORS)
      object.class::PROPERTY_DESCRIPTORS.each_pair do |k, v|
        properties[k.to_clr_string] = List.of(System::String).new
        properties[k.to_clr_string].replace v.map{|e| e.to_clr_string}
      end
    else
      # Default to String properties
      properties["string"] = List.of(System::String).new
      properties["string"].replace (object.methods -
Object.instance_methods).map{|e| e.to_clr_string}
    end
    wrapper_base_type = TypeGenerator.generate("#{wrapper_name}Base",
properties)
    base_instance = System::Activator.create_instance wrapper_base_type
    eval <<EOS
      class #{wrapper_name} < base_instance.class
        def initialize(original)
          self.on_get = lambda do |prop|
            original.send prop
          end
          self.on_set = lambda do |prop, val|
            original.send "\#{prop}=", val
          end
        end
      end
      return #{wrapper_name} # return the class
EOS
  end
end
class Person
  attr_accessor :test
  PROPERTY_DESCRIPTORS = { :int => [:test] }
end
wrapper = WrapperGenerator.new
wrapped = wrapper.wrap(Person.new)
puts "Wrapped"
# wrapped.test = "35" # properly generates Exception: Cannot convert
String to Fixnum
wrapped.test = 35 # !!!!! Crashes here !!!!!
puts "Assigned"
puts wrapped.test, wrapped.test.inspect, wrapped.test.class
________________________________
_______________________________________________
Ironruby-core mailing list
Ironruby-core at rubyforge.org<mailto:Ironruby-core at rubyforge.org>
http://rubyforge.org/mailman/listinfo/ironruby-core
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://rubyforge.org/pipermail/ironruby-core/attachments/20110614/cac1da2d/attachment-0001.html>
Sickboy
2011-Jun-14  17:56 UTC
[Ironruby-core] WPF Databinding with RubyObjects, continuation, dynamically create wrappers with strong typed properties
Thanks! Currently on my way with the backup plan.
But here?s the C# and Ruby for the dynamic implementation:
C#
namespace GenerateType
{
    public class TypeGenerator
    {
        public delegate object GetPropertyDelegate(string propertyName);
        public delegate object SetPropertyDelegate(string propertyName, object
value);
        public static Type Generate(string className, Dictionary<string,
List<string>> properties)
        {
            AssemblyName asmName = new AssemblyName("BindingTypes");
            AssemblyBuilder asmBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(asmName,
AssemblyBuilderAccess.Run);
            ModuleBuilder modBuilder =
asmBuilder.DefineDynamicModule("Types");
            TypeBuilder typeBuilder = modBuilder.DefineType(className,
                        TypeAttributes.Public |
                        TypeAttributes.Class |
                        TypeAttributes.AutoClass |
                        TypeAttributes.AnsiClass |
                        TypeAttributes.BeforeFieldInit |
                        TypeAttributes.AutoLayout);
            FieldBuilder getFieldBuilder =
typeBuilder.DefineField("OnGet", typeof(GetPropertyDelegate),
FieldAttributes.Public);
            FieldBuilder setFieldBuilder =
typeBuilder.DefineField("OnSet", typeof(SetPropertyDelegate),
FieldAttributes.Public);
            MethodAttributes getSetAttr = MethodAttributes.Public |
MethodAttributes.SpecialName | MethodAttributes.HideBySig;
            Type type = null;
            foreach (string s in properties.Keys)
            {
                type = null;
                switch (s)
                {
                    case "float":
                        type = typeof(float);
                        break;
                    case "int":
                        type = typeof(int);
                        break;
                    case "string":
                        type = typeof(string);
                        break;
                    case "bool":
                        type = typeof(bool);
                        break;
                    //case "dynamic":
                    //    type = dynamic;
                }
                if (type != null)
                {
                    GenerateProperties(properties[s], type, typeBuilder,
getSetAttr, getFieldBuilder, setFieldBuilder);
                }
            }
            return typeBuilder.CreateType();
        }
        public static void GenerateProperties(List<string> properties,
Type type, TypeBuilder typeBuilder, MethodAttributes getSetAttr, FieldBuilder
getFieldBuilder, FieldBuilder setFieldBuilder)
        {
            foreach (string propertyName in properties)
            {
                PropertyBuilder propBuilder =
typeBuilder.DefineProperty(propertyName, PropertyAttributes.None,
typeof(object), new Type[] {});
                MethodBuilder getter = typeBuilder.DefineMethod("get_"
+ propertyName,
                                   getSetAttr,
                                   type,
                                   Type.EmptyTypes);
                ILGenerator ilGen = getter.GetILGenerator();
                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Ldfld, getFieldBuilder);
                ilGen.Emit(OpCodes.Ldstr, propertyName);
                ilGen.Emit(OpCodes.Callvirt,
typeof(GetPropertyDelegate).GetMethod("Invoke"));
                if (type != typeof(string))
                {
                    //ilGen.Emit(OpCodes.Unbox, type);
                }
                ilGen.Emit(OpCodes.Ret);
                // Define the "set" accessor method for CustomerName.
                MethodBuilder setter = typeBuilder.DefineMethod("set_"
+ propertyName,
                                               getSetAttr,
                                               null,
                                               new Type[] { type });
                ilGen = setter.GetILGenerator();
                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Ldfld, setFieldBuilder);
                ilGen.Emit(OpCodes.Ldstr, propertyName);
                ilGen.Emit(OpCodes.Ldarg_1);
                if (type == typeof(int) || type == typeof(float))
                {
                    ilGen.Emit(OpCodes.Box, type);
                }
                ilGen.Emit(OpCodes.Callvirt,
typeof(SetPropertyDelegate).GetMethod("Invoke"));
                ilGen.Emit(OpCodes.Pop);
                ilGen.Emit(OpCodes.Ret);
                // Last, we must map the two methods created above to our
PropertyBuilder to
                // their corresponding behaviors, "get" and
"set" respectively.
                propBuilder.SetGetMethod(getter);
                propBuilder.SetSetMethod(setter);
            }
        }
    }
}
Ruby:
include System::Data
include System::Windows::Data
include System::ComponentModel
include GenerateType 
class WrapperGenerator
  def initialize
    @wrapper_cache = {}
  end
  def wrap(ruby_object)
    if ruby_object.is_a? Array
      ruby_object.map {|o| wrap(o) }
    else
      cache(ruby_object) unless cached(ruby_object)
      wrapper_class = cached(ruby_object)
      wrapper_class.new(ruby_object)
    end
  end
  def invalidate
    @wrapper_cache.clear
  end
private
  def cached(object)
    @wrapper_cache[object.class.name]
  end
  def cache(object)
    @wrapper_cache[object.class.name] = generate_wrapper(object)
  end
  def generate_wrapper(object)
    wrapper_name = "#{object.class.name}Wrapper"
    properties = Dictionary.of(System::String, List.of(System::String)).new
    if defined?(object.class::PROPERTY_DESCRIPTORS)
      object.class::PROPERTY_DESCRIPTORS.each_pair do |k, v|
        properties[k.to_clr_string] = List.of(System::String).new
        properties[k.to_clr_string].replace v.map{|e| e.to_clr_string}
      end
    else
      # Default to String properties
      properties["string"] = List.of(System::String).new
      properties["string"].replace (object.methods -
Object.instance_methods).map{|e| e.to_clr_string}
    end
    wrapper_base_type = TypeGenerator.generate("#{wrapper_name}Base",
properties)
    base_instance = System::Activator.create_instance wrapper_base_type
    eval <<EOS
      class #{wrapper_name} < base_instance.class
        def initialize(original)
          self.on_get = lambda do |prop|
            original.send prop
          end
          self.on_set = lambda do |prop, val|
            original.send "\#{prop}=", val
          end
        end
      end
      return #{wrapper_name} # return the class
EOS
  end
end
class Person
  attr_accessor :test
  PROPERTY_DESCRIPTORS = { :int => [:test] }
end
wrapper = WrapperGenerator.new
wrapped = wrapper.wrap(Person.new)
puts "Wrapped"
# wrapped.test = "35" # properly generates Exception: Cannot convert
String to Fixnum
wrapped.test = System::Int16.new(35) # !!!!! Crashes here !!!!!
puts "Assigned"
puts wrapped.test, wrapped.test.inspect, wrapped.test.class
From: Tomas Matousek 
Sent: Tuesday, June 14, 2011 7:49 PM
To: ironruby-core at rubyforge.org 
Subject: Re: [Ironruby-core] WPF Databinding with RubyObjects,
continuation,dynamically create wrappers with strong typed properties
Your backup plan might actually be better ? emitting code at runtime is
definitely slower than loading already compiled code.
 
You?re still emitting some wrong instructions. Can you send your new code?
 
Tomas
 
From: ironruby-core-bounces at rubyforge.org [mailto:ironruby-core-bounces at
rubyforge.org] On Behalf Of Sickboy
Sent: Tuesday, June 14, 2011 10:03 AM
To: ironruby-core at rubyforge.org
Subject: Re: [Ironruby-core] WPF Databinding with RubyObjects, continuation,
dynamically create wrappers with strong typed properties
 
Thanks! Still new to .NET and especially this stuff.
 
The Box/Unbox seems to have worked, except that if I set e.g 35 as new value,
when reading the value back, something completely different comes back, e.g;
150007660, but correct class Fixnum.
This number seems randomized, and changes upon accessing the getter for the
property more than once.
 
Any suggestions or alternatives welcome.
My backup plan is to generate the C# classes from Ruby dynamically during
development and saving them into a .cs file to be compiled with exe/dll.
 
Regards
 
 
From: Tomas Matousek 
Sent: Tuesday, June 14, 2011 6:05 PM
To: ironruby-core at rubyforge.org 
Subject: Re: [Ironruby-core] WPF Databinding with RubyObjects,
continuation,dynamically create wrappers with strong typed properties
 
My guess would be that you?re not boxing the value.
You need to emit OpCodes.Box to convert bool/int/? to an Object before calling
Invoke in setter. The setter should also return Object (your?s is void). In
getter you need to use OpCodes.Unbox before returning.
I?d also recommend using Func<> delegate instead of your custom delegate
types if possible.
 
Tomas
 
From: ironruby-core-bounces at rubyforge.org [mailto:ironruby-core-bounces at
rubyforge.org] On Behalf Of Sickboy
Sent: Tuesday, June 14, 2011 8:38 AM
To: ironruby-core at rubyforge.org
Subject: [Ironruby-core] WPF Databinding with RubyObjects, continuation,
dynamically create wrappers with strong typed properties
 
Hello,
 
I recently stumbled upon this awesome code:
http://rubyforge.org/pipermail/ironruby-core/2008-December/003377.html
It does exactly what I need; dynamically wrapping my RubyObject into a CLR class
with CLR properties, except that it?s designed only for string properties.
 
I?ve adjusted the code to support a number of types, incl int, bool and float.
 
However the CLR crashes when-ever I assign a value to a non-string property, e.g
float or int.
?The runtime has encountered a fatal error. The address of the error was at
0x5935788d, on thread 0x1adc. The error code is 0xc0000005. This error may be a
bug in the CLR or in the unsafe or non-verifiable portions of user code. Common
sources of this bug include user marshaling errors for COM-interop or PInvoke,
which may corrupt the stack.?
 
Any assistance would be deeply appreciated.
 
In essence, instead of using typeof(string) inside the TypeGenerator.Generate
method, i use e.g; typeof(int) or typeof(float)
This is my current code:
 
C#:
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
 
namespace GenerateType
{
    public class TypeGenerator
    {
        public delegate object GetPropertyDelegate(string propertyName);
        public delegate object SetPropertyDelegate(string propertyName, object
value);
 
        public static Type Generate(string className, Dictionary<string,
List<string>> properties)
        {
            AssemblyName asmName = new AssemblyName("BindingTypes");
            AssemblyBuilder asmBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(asmName,
AssemblyBuilderAccess.Run);
            ModuleBuilder modBuilder =
asmBuilder.DefineDynamicModule("Types");
            TypeBuilder typeBuilder = modBuilder.DefineType(className,
                        TypeAttributes.Public |
                        TypeAttributes.Class |
                        TypeAttributes.AutoClass |
                        TypeAttributes.AnsiClass |
                        TypeAttributes.BeforeFieldInit |
                        TypeAttributes.AutoLayout);
 
 
            FieldBuilder getFieldBuilder =
typeBuilder.DefineField("OnGet", typeof(GetPropertyDelegate),
FieldAttributes.Public);
            FieldBuilder setFieldBuilder =
typeBuilder.DefineField("OnSet", typeof(SetPropertyDelegate),
FieldAttributes.Public);
 
            MethodAttributes getSetAttr = MethodAttributes.Public |
MethodAttributes.SpecialName | MethodAttributes.HideBySig;
 
            Type type = null;
 
            foreach (string s in properties.Keys)
            {
                type = null;
                switch (s)
                {
                    case "float":
                        type = typeof(float);
                        break;
                    case "int":
                        type = typeof(int);
                        break;
                    case "string":
                        type = typeof(string);
                        break;
                    case "bool":
                        type = typeof(bool);
                        break;
                    //case "dynamic":
                    //    type = dynamic;
                }
                if (type != null)
                {
                    GenerateProperties(properties[s], type, typeBuilder,
getSetAttr, getFieldBuilder, setFieldBuilder);
                }
            }
            return typeBuilder.CreateType();
        }
 
        public static void GenerateProperties(List<string> properties,
Type type, TypeBuilder typeBuilder, MethodAttributes getSetAttr, FieldBuilder
getFieldBuilder, FieldBuilder setFieldBuilder)
        {
            foreach (string propertyName in properties)
            {
                PropertyBuilder propBuilder =
typeBuilder.DefineProperty(propertyName, PropertyAttributes.None,
typeof(object), new Type[] {});
                MethodBuilder getter = typeBuilder.DefineMethod("get_"
+ propertyName,
                                   getSetAttr,
                                   type,
                                   Type.EmptyTypes);
 
                ILGenerator ilGen = getter.GetILGenerator();
 
                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Ldfld, getFieldBuilder);
                ilGen.Emit(OpCodes.Ldstr, propertyName);
                ilGen.Emit(OpCodes.Callvirt,
typeof(GetPropertyDelegate).GetMethod("Invoke"));
                ilGen.Emit(OpCodes.Ret);
 
                // Define the "set" accessor method for CustomerName.
                MethodBuilder setter = typeBuilder.DefineMethod("set_"
+ propertyName,
                                               getSetAttr,
                                               null,
                                               new Type[] { type });
 
                ilGen = setter.GetILGenerator();
 
                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Ldfld, setFieldBuilder);
                ilGen.Emit(OpCodes.Ldstr, propertyName);
                ilGen.Emit(OpCodes.Ldarg_1);
                ilGen.Emit(OpCodes.Callvirt,
typeof(SetPropertyDelegate).GetMethod("Invoke"));
                ilGen.Emit(OpCodes.Pop);
                ilGen.Emit(OpCodes.Ret);
 
                // Last, we must map the two methods created above to our
PropertyBuilder to
                // their corresponding behaviors, "get" and
"set" respectively.
                propBuilder.SetGetMethod(getter);
                propBuilder.SetSetMethod(setter);
            }
        }
    }
}
 
 
 
 
Ruby Code:
 
include System::Data
include System::Windows::Data
include System::ComponentModel
 
include GenerateType 
class WrapperGenerator
  def initialize
    @wrapper_cache = {}
  end
 
  def wrap(ruby_object)
    if ruby_object.is_a? Array
      ruby_object.map {|o| wrap(o) }
    else
      cache(ruby_object) unless cached(ruby_object)
      wrapper_class = cached(ruby_object)
      wrapper_class.new(ruby_object)
    end
  end
 
  def invalidate
    @wrapper_cache.clear
  end
private
  def cached(object)
    @wrapper_cache[object.class.name]
  end
 
  def cache(object)
    @wrapper_cache[object.class.name] = generate_wrapper(object)
  end
 
  def generate_wrapper(object)
    wrapper_name = "#{object.class.name}Wrapper"
    properties = Dictionary.of(System::String, List.of(System::String)).new
 
    if defined?(object.class::PROPERTY_DESCRIPTORS)
      object.class::PROPERTY_DESCRIPTORS.each_pair do |k, v|
        properties[k.to_clr_string] = List.of(System::String).new
        properties[k.to_clr_string].replace v.map{|e| e.to_clr_string}
      end
    else
      # Default to String properties
      properties["string"] = List.of(System::String).new
      properties["string"].replace (object.methods -
Object.instance_methods).map{|e| e.to_clr_string}
    end
 
    wrapper_base_type = TypeGenerator.generate("#{wrapper_name}Base",
properties)
    base_instance = System::Activator.create_instance wrapper_base_type
 
    eval <<EOS
      class #{wrapper_name} < base_instance.class
        def initialize(original)
          self.on_get = lambda do |prop|
            original.send prop
          end
 
          self.on_set = lambda do |prop, val|
            original.send "\#{prop}=", val
          end
        end
      end
      return #{wrapper_name} # return the class
EOS
  end
end
 
class Person
  attr_accessor :test
  PROPERTY_DESCRIPTORS = { :int => [:test] }
end
 
wrapper = WrapperGenerator.new
wrapped = wrapper.wrap(Person.new)
puts "Wrapped"
# wrapped.test = "35" # properly generates Exception: Cannot convert
String to Fixnum
wrapped.test = 35 # !!!!! Crashes here !!!!!
puts "Assigned"
puts wrapped.test, wrapped.test.inspect, wrapped.test.class
--------------------------------------------------------------------------------
_______________________________________________
Ironruby-core mailing list
Ironruby-core at rubyforge.org
http://rubyforge.org/mailman/listinfo/ironruby-core
--------------------------------------------------------------------------------
_______________________________________________
Ironruby-core mailing list
Ironruby-core at rubyforge.org
http://rubyforge.org/mailman/listinfo/ironruby-core
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://rubyforge.org/pipermail/ironruby-core/attachments/20110614/c13b1266/attachment-0001.html>