Setting properties by name

A

Alexander Walker

Hello

I would like to write a method that allows me to pass a reference to an instance
of a class, the name of a property of that class and a value to set that
property to, the method would then set the property of the instance to the value

here is an example of what the method might look like

public void SetProperty(object instance, string property, object value)
{
//TODO: set the named property of the instance with the value
}

The method could be called like this

SetProperty(myClassInstance, "MyProperty", "My Value");

How would such a method be written? how do you access the members of an instance
in a late bound manner, or is it even possible to pass a reference to the actual
property like so

SetProperty(myClassInstance, myClassInstance.MyProperty, "The Value");

Where the method is not taking the value of myClassInstance.MyProperty but the
reference to the actual property so that it can set its value, is this possible?

Thanks

Alex
 
M

Marc Gravell

Reflection:

instance.GetType().GetProperty(property).SetValue(instance, value, null);

(assumes public, writeable, instance property)

Marc
 
S

Stoitcho Goutsev \(100\)

Alexander,

Look at the .net reflection.

The code for setting the property would look something like this:

Type t = myClassInstance.GetType();
PropertyInfo pi = t.GetProperty(MyProperty);
pi.SetValue(myClassInstance, myValue, null);

Type.GetProperty method has more than one overload. You may need to use some
of the others depending on the visibility of the property.

If you want to pass "instance of a property" you can use the PropertyInfo
class.
 
C

Claes Bergefall

Here are some methods I've been using to accomplish that (both Set and Get).
They're in VB.NET though so you'll have to translate them:

' Description:
' Calls the get method for a property on an object using reflection.
GetProperty
' searches the inheritance chain until it finds a match. All access
levels
' (private, public etc) are supported
' Parameters:
' name - Name of property to get
' object - Object on which to get the property value
' params - Optional parameters to the property
' Return value:
' The returned value of the property's get method
' Exceptions:
' MissingMemberException - No property or get method matching the
specified name or parameters was found
' MissingMethodException - No get method was found (property is
write-only)
Public Shared Function GetProperty(ByVal name As String, ByVal obj As
Object, ByVal ParamArray params() As Object) As Object
Dim objectType As Type = obj.GetType
Dim flags As BindingFlags = BindingFlags.Instance Or _
BindingFlags.Static Or _
BindingFlags.NonPublic Or _
BindingFlags.Public

Dim propertyInfo As PropertyInfo
Dim types(params.Length - 1) As Type
Dim index As Integer
For index = 0 To params.Length - 1
types(index) = params(index).GetType
Next

While Not objectType Is Nothing
propertyInfo = objectType.GetProperty(name, flags, Nothing, Nothing,
types, Nothing)
If propertyInfo Is Nothing Then
objectType = objectType.BaseType
Else
Exit While
End If
End While

If propertyInfo Is Nothing Then
Throw New MissingMemberException(obj.GetType.FullName, "")
ElseIf Not propertyInfo.CanRead Then
Throw New MissingMethodException(obj.GetType.FullName, "")
Else
Return propertyInfo.GetValue(obj, params)
End If
End Function

' Description:
' Calls the set method for a property on an object using reflection.
SetProperty
' searches the inheritance chain until it finds a match. All access
levels
' (private, public etc) are supported
' Parameters:
' name - Name of property to set
' object - Object on which to set the property value
' value - Value to assign to the property
' params - Optional parameters to the property
' Return value:
' None
' Exceptions:
' MissingMemberException - No property matching the specified name or
parameters was found
' MissingMethodException - No set method was found (property is
read-only)
Public Shared Sub SetProperty(ByVal name As String, ByVal obj As Object,
ByVal value As Object, ByVal ParamArray params() As Object)
Dim objectType As Type = obj.GetType
Dim flags As BindingFlags = BindingFlags.Instance Or _
BindingFlags.Static Or _
BindingFlags.NonPublic Or _
BindingFlags.Public

Dim propertyInfo As PropertyInfo
Dim types(params.Length - 1) As Type
Dim index As Integer
For index = 0 To params.Length - 1
types(index) = params(index).GetType
Next

While Not objectType Is Nothing
propertyInfo = objectType.GetProperty(name, flags, Nothing, Nothing,
types, Nothing)
If propertyInfo Is Nothing Then
objectType = objectType.BaseType
Else
Exit While
End If
End While

If propertyInfo Is Nothing Then
Throw New MissingMemberException(obj.GetType.FullName, "")
ElseIf Not propertyInfo.CanWrite Then
Throw New MissingMethodException(obj.GetType.FullName, "")
Else
propertyInfo.SetValue(obj, value, params)
End If
End Sub


/claes
 
H

Herfried K. Wagner [MVP]

Claes Bergefall said:
Here are some methods I've been using to accomplish that (both Set and
Get). They're in VB.NET though so you'll have to translate them:

Mhm... You could use 'CallByName' in VB.NET instead of these methods ;-).
 
A

Alexander Walker

Here are the methods I came up with

delegate object GetPropertyCallback(object parent, object control,
string propertyName);
delegate void SetPropertyCallback(object parent, object control, string
propertyName, object value);

public object GetProperty(object parent, object control, string
propertyName)
{
Control instance = null;
if (parent != null)
{
instance = (Control)parent;
}
else
{
instance = (Control)control;
}
if (instance.InvokeRequired)
{
GetPropertyCallback d = new GetPropertyCallback(GetProperty);
return instance.Invoke(d, new object[] { parent, control,
propertyName });
}
else
{
return
control.GetType().GetProperty(propertyName).GetValue(control, null);
}
}

public void SetProperty(object parent, object control, string
propertyName, object value)
{
Control instance = null;
if (parent != null)
{
instance = (Control)parent;
}
else
{
instance = (Control)control;
}
if (instance.InvokeRequired)
{
SetPropertyCallback d = new SetPropertyCallback(SetProperty);
instance.Invoke(d, new object[] { parent, control, propertyName,
value });
}
else
{
control.GetType().GetProperty(propertyName).SetValue(control,
value, null);
}
}

I needed a generic way of accessing control properties in a thread safe manner,
the reason for the parent and the control properties are for those cases where
the "control" that you are trying to access does not inherit from control and
does not have an InvokeRequired property, the particular situation I face
involved a progress bar on a status strip control, the progress bar didn't
inherit from control and so didn't have an InvokeRequired property, so I passed
the status strip as the parent

Thanks

Alex
 
M

Marc Gravell

Some observations:

Since you always expect parent and control to be Controls, why not specify
them as Control on the interface?

The "callback" isn't really what I would call a callback - normally this
involves an AsyncResult or somesuch; perhaps just call it
GetPropertyDelegate?

I can't recall (and don't have an IDE handy), but some of the Invoke methods
accept a params parameter which makes the call easier; and looks like they
should be static methods?

Other than that, it looks like it should work,

Marc
 
M

Marc Gravell

ammendment; I see what you mean about the child; if it must be that way, I'd
have 2 versions of each

public static object GetProperty(object obj, string propertyName) {
return GetProperty(obj as Control, obj, propertyName);
}

public static object GetProperty(Control parent, object obj, string
propertyName) {
if(parent==null || !parent.InvokeRequired) {
// call directly
}
else {
// invoke (private) delegate
}
}

===

Done this way, I can pass any object to the first version of GetProperty; if
it is a control it will be automatically passed to the right thread; if I
know I have an object that needs to be accessed on a particular thread I can
use the second version. You could consider replacing Control with
ISynchronizeInvoke, but that is probably overkill.

Marc
 
C

Claes Bergefall

Hmm, guess I could. Didn't know about that one :)
Does it work with private members as well?

/claes
 
T

TerryFei

Hi Alexander,

I just want to check how things are going and whether or not your problem
has been resolved. If there is any question, please feel free to join the
community and we are here to support you at your convenience. Thanks again!

Best Regards,

Terry Fei[MSFT]
Microsoft Community Support
Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)

--------------------
 
A

Alexander Walker

Hello Terry,

I have been able to use the two methods that I posted earlier to satisfy my
needs

Thank you

Alex
 
T

TerryFei

Hi Alex,
Thanks for your update! :)

I am glad to know that the problem has been resolved now. Thanks for
participating the community!

Best Regards,

Terry Fei [MSFT]
Microsoft Community Support
Get Secure! www.microsoft.com/security

--------------------
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top