Get property Type and convert String to corresponding Type
Asked Answered
R

3

6

I am using CSOM to update some Task of a Project Server Project.

Which property has to be updated is not defined the code finds out dynamically what to update based on the property name as String.

For better understanding I wore a simplified version of my code

//fieldName = "ActualWorkTimeSpan"; value = "16:00:00";
private void Start(string fieldName, string value)
{
    DraftTask draftTask = GetDraftTask();

    Update(draftTask, fieldName, value);

    PublishAndCheckin(draftTask);
}

private static void Update(DraftTask draftTask, string fieldName, string value)
{
    // skip updating if field is Equal
    if (GetPropValue(draftTask, fieldName).ToString() == value)
        return;

    // update of the task
    SetPropValue(draftTask, fieldName, value);

}

private static object GetPropValue(object src, string propName)
{
    return src.GetType().GetProperty(propName).GetValue(src, null);
}

private static void SetPropValue(DraftTask src, string propName, object value)
{
    src.GetType().GetProperty(propName).SetValue(src, value);
}

I can use GetPropValue() without problem but for SetPropValue() I would need the value to be in the right type.

In this case it would be "System.TimeSpan" for the property "ActualWorkTimeSpan". So I would need to convert the string "15:00:00" to TimeSpan.

It would be easy to do if it were TimeSpan every time, but I could be that the Field "Cost" is set to be updated.

Update(draftTask, "Cost", "500");

So my question is if it is Possible to find out what type the field has and than convert my value to the same type.

Redfin answered 16/11, 2017 at 13:35 Comment(14)
Why do you need it to be in the right type? SetValue takes an object type anyway.Succeed
Also, I don't think you understand what the ref keyword does, I suggest you go read up on that too.Succeed
@DavidG; only if the target property is an object as well. His source data is always a string, so it clearly has to be converted firstMichaelemichaelina
@Michaelemichaelina OP is using reflection, the parameters of SetValue are object. I'm not sure what you are suggesting.Succeed
SetPropValue takes parameter object value but this is always being called with a string. I suggest the method signature is changed if this is always going to be the case.Garman
@Succeed I am suggestion that the target class DraftTask has a property signature public TimeSpan ActualWorkTimeSpan. If you call SetValue with a string on that property, it will fail at runtime without conversion.Michaelemichaelina
@Michaelemichaelina Yes, and as CalC suggests, it's the value that is passed in that is the problem. The method should be changed to take an object, or even make it generic.Succeed
What's the reason why all your data is in string in the first place?Spermary
Btw, instead of "ActualWorkTimeSpan" you used use nameof(DraftTask.ActualWorkTimeSpan) learn.microsoft.com/en-us/dotnet/csharp/language-reference/…Spermary
@RandRandom, his question is simplified. "(...)which property has to be updated is not defined the code finds out dynamically what to update based on the property name".Michaelemichaelina
Can you clarify if you are looking to parse string values or otherwise? Also, why are you using reflection?Garman
Your check for equality is also seriously flawed. If the Type doesn't override ToString it will always compare the values based on the name of the Type, so objects will ALWAYS return as being unequal, unless the value is literally the name of the Type.Harlan
@RandRandom - you are totally correct. However, if the OP can do that, they really shouldn't be using reflection. I can only assume the fieldnames are in a drop down or config file and that Update(ref draftTask, "ActualWorkTimeSpan", "15:00:00"); is just an exampleGarman
Thanks for all your feedback. First yes the Update() is just an example. I will change it a bit later to clarify things. The ref could also be removed from my example. About the equality check I am still just trying around at the moment so it is fine. I am still learning thanks again for all your feedback.Redfin
H
22

I use TypeDescriptor.GetConverter that takes a Type and returns a TypeConverter that knows how to convert a string to the specified Type.

You can then call TypeConverter.ConvertFromString to convert the string to the required Type.

Your code would look like:

var propType = src.GetType().GetProperty(propName).PropertyType;
var converter = TypeDescriptor.GetConverter(propType);
var convertedObject = converter.ConvertFromString(src);
Harlan answered 16/11, 2017 at 13:45 Comment(2)
This will work of course but it'really just papering over the fact that the method signature is wrong in the first place.Succeed
it throws : System.ArgumentException : Object of type 'System.String' cannot be converted to type 'System.Int32'.Pulliam
C
1

You can do this, by using Convert.ChangeType method.

private static void SetPropValue(DraftTask src, string propName, object value)
{
    var property = src.GetType().GetProperty(propName);
    var valueToSet = Convert.ChangeType(value, property.PropertyType);
    property.SetValue(src, valueToSet);
}

ref, is useless in this case. It is used when you assign the parameter in the called method and have it also be assigned at the calling site (the scope of the calling method).

Cordiform answered 16/11, 2017 at 13:41 Comment(1)
and assign new object to that object should be and assign new object to that referenceSpermary
S
0

The simplest option is to change the method signature to be generic or take an object type and actually pass in the correct data type in the first place. For example:

private static void Update(DraftTask draftTask, string fieldName, object value)
{
    //snip
}

Or generic:

private static void Update<T>(DraftTask draftTask, string fieldName, T value)
{
    //snip
}

And now you call it with the correct type, for example:

var timeSpan = new TimeSpan(...);
Update(ref draftTask, "ActualWorkTimeSpan", timeSpan);
Succeed answered 16/11, 2017 at 13:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.