Trying to map two different types to one value

2019-08-13 06:31发布

I have a DataMember that I need to be filled in by an api json string...

[DataContract]
public class Values
{
    [DataMember]
    public object value { get; set; }
}

API json string:

[
    {
        "type": "text",
        "values": [
            {
                "value": "Text that is in textfield"
            }
        ]
    },
    {
        "type": "category",
        "values": [
            {
                "value": {
                    "text": "Category title",
                    "color": "#000000"
                }
            }
        ]
    }
]

I map this string to a strong typed object Field like so:

    private List<Field> PrepFieldObject(string response)
    {
        using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(response)))
        {
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List<Field>));
            return (List<Field>)serializer.ReadObject(stream);
        }
    }

but when it gets to mapping Values.value, it throws a hissy fit... I tried solving it like this:

[DataContract]
public class Values
{
    [DataMember]
    public object value
    {
        get {
            return xamlValue;
        }
        set
        {                     
            xamlValue = new Value();

            if( value is string )
            {
                 xamlValue.text = (string)value; // This works fine
            }
            else
            {

                Value theValue = value as Value;
                try
                {
                    xamlValue.text = theValue.text; // Can't get hold of .text even though it does exist in the json.
                    xamlValue.color = theValue.color;
                }
                catch (Exception e)
                {
                }
            }
        }
    }
    public Value xamlValue { get; set; }
}

[DataContract]
public class Value
{
    [DataMember]
    public string text { get; set; }
    [DataMember]
    public string color { get; set; }
}

But it doesn't let me access properties of the object (I guess because they were never mapped by the DataContract)

I've tried adding

[KnownType(typeof(Value))]
[KnownType(typeof(string))]

but that doesn't help either :'(

6条回答
\"骚年 ilove
2楼-- · 2019-08-13 07:02

I think you can use reflection to to access your object's property value. Try changing your setter's else part as

else
    {

        Value theValue = value as Value;
        try
        {   
            // pass the object and the property name you're trying to get hold of
            xamlValue.text = PropertyHasValue(theValue, "text"); // Can't get hold of .text even though it does exist in the json. 
            xamlValue.color = PropertyHasValue(theValue, "color");
        }
        catch (Exception e)
        {
        }
    }

And the reflection method

// using reflection to get the object's property value
public static String PropertyHasValue(object obj, string propertyName)
{
    try
    {
        if (obj != null)
        {
            PropertyInfo prop = obj.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public);
            if (prop != null)
            {
                string sVal = String.Empty;
                object val = prop.GetValue(obj, null);

                if (prop.PropertyType != typeof(System.DateTime?))
                    sVal = Convert.ToString(val);
                else // format the date to contain only the date portion of it
                    sVal = Convert.ToDateTime(val).Date.ToString("d"); ;

                if (sVal != null)
                {
                    return sVal;
                 }
             }
        }

        return null;
    }
    catch
    {
        return null;
    }
}
查看更多
Animai°情兽
3楼-- · 2019-08-13 07:10

You have to cast it to whatever type the text property belongs to.

((SomeType)value).text
查看更多
萌系小妹纸
4楼-- · 2019-08-13 07:11

If you want a string or the defined string representation of the object use:

String valueAsString = value.ToString()

That is assuming that the other types (besides string) override the ToString() method to provide a meaningful string representation of the object.

Otherwise you would need to use:

KnownValueType kvt = value as KnownValueType
if(kvt!=null)
{
  //access known type properties here
}
查看更多
放我归山
5楼-- · 2019-08-13 07:13

You can just use the operator is, but you have to use it for each value that value can assume:

if (value is String)
{
    //do something
}
else if (value is ...)
...

You can read more about is here.

查看更多
仙女界的扛把子
6楼-- · 2019-08-13 07:21

You will have to use type-casting. Example string:

string abc = (string)value.text;

OR (preferably)

ComplexType comp = value as ComplexType;

UPDATE:

When you are trying to serialize a JSON object and convert it to a strongly-typed object (something my ComplexType is an example of), its important to have the same names for the properties as is in the JSON. After serialization, you should be able to access the property values.

Hope this helps!!!

查看更多
闹够了就滚
7楼-- · 2019-08-13 07:23

You COULD use a dynamic type:

DataContract]
public class Values
{
    [DataMember]
    public dynamic value { get; set; }
}

More about Dynamics

查看更多
登录 后发表回答