1

I'm using the following code to create an Expression based property setter:

Public Function PropertySetExpression(Of TObjectType, TPropertyType)(propertyName As String) As Expression(Of Action(Of TObjectType, TPropertyType))
   Dim paramExpression = Expression.Parameter(GetType(TObjectType), "value")
   Dim propertyExpression = Expression.[Property](paramExpression, propertyName)
   Dim getter = Expression.Lambda(Of Func(Of TObjectType, TPropertyType))(propertyExpression, paramExpression)

   Dim member = CType(getter.Body, MemberExpression)
   Dim param = Expression.Parameter(GetType(TPropertyType), "value")

   Return Expression.Lambda(Of Action(Of TObjectType, TPropertyType))(Expression.Assign(member, param), getter.Parameters(0), param)
End Function

And this works perfectly if TProperty is specified at compile time. But sometimes I need a more flexible architecture, and want to use Object instead of a more specific type, and this also works fine if TProperty is a reference type. But if it's a value type, I get this error:

System.ArgumentException: 'Expression of type 'System.Int32' cannot be used for return type 'System.Object''

In this answer to a similar question, but about a property getter, Jon Skeet explains how to fix this for a property getter, by inserting a Convert expression to box the value type to an object, but I can't figure out how to apply this in the reverse direction to unbox the object before setting back into a value type.

How might I do this?

Update, as requested by comment:

A normal property setter would be something like:

obj.Id = 3

The above code is so that I could get a function dynamically to accomplish the same thing:

Dim setter = PropertySetExpression(Of TMyObject, Integer)("Id").Compile()

...

setter(obj, 3)

The reason to do this would be in scenarios where I want to be able to set properties specified in, say, a text file, but with the fast performance of a property setter.

As I say in the post, this works fine. But sometimes I don't even know the data type at compile time, so I want to do:

Dim setter = PropertySetExpression(Of TMyObject, Object)(prop_name).Compile()

And let the setter deal with the boxing/unboxing from the actual data type (Integer in this case) to Object.

Community
  • 1
  • 1
Joshua Frank
  • 13,120
  • 11
  • 46
  • 95

0 Answers0