Json的float单精度浮点数类型支持Can't assign value '11.88' (type System.Double) to type System.Single

本文介绍了一个关于litjson在Unity中处理float类型数据时出现的问题,并提供了详细的解决方案。通过修改JsonMapper.cs脚本,增加了对float类型的导出和导入支持。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天遇到个问题Can’t assign value ‘11.88’ (type System.Double) to type System.Single
litjson不支持单精度浮点数float

只用修改JsonMapper.cs脚本就可以,一共修改两处

1.在JsonMapper.cs脚本里面增加如下代码
            #region  litjson support float  modified by codingriver wangguoqing 2018-10-29
            base_exporters_table[typeof(float)] =
                delegate (object obj, JsonWriter writer) {
                    writer.Write((float)obj);
                };
            #endregion

增加到如下位置:
在这里插入图片描述

2.在JsonMapper.cs脚本里面增加如下代码
            #region  litjson support float  modified by codingriver  2018-10-29
            importer = delegate (object input) {
                return Convert.ToSingle((double)input);
            };

            RegisterImporter(base_importers_table, typeof(double),
                               typeof(float), importer);
            #endregion

增加后是这样的
在这里插入图片描述

3.最后贴上修改后的JsonMapper.cs代码:
#region Header
/**
 * JsonMapper.cs
 *   JSON to .Net object and object to JSON conversions.
 *
 * The authors disclaim copyright to this source code. For more details, see
 * the COPYING file included with this distribution.
 **/
#endregion


using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using ILRuntime.Runtime.Intepreter;
using ILRuntime.Runtime.Stack;
using ILRuntime.CLR.Method;
using ILRuntime.CLR.Utils;

namespace LitJson
{
    internal struct PropertyMetadata
    {
        public MemberInfo Info;
        public bool       IsField;
        public Type       Type;
    }


    internal struct ArrayMetadata
    {
        private Type element_type;
        private bool is_array;
        private bool is_list;


        public Type ElementType {
            get {
                if (element_type == null)
                    return typeof (JsonData);

                return element_type;
            }

            set { element_type = value; }
        }

        public bool IsArray {
            get { return is_array; }
            set { is_array = value; }
        }

        public bool IsList {
            get { return is_list; }
            set { is_list = value; }
        }
    }


    internal struct ObjectMetadata
    {
        private Type element_type;
        private bool is_dictionary;

        private IDictionary<string, PropertyMetadata> properties;


        public Type ElementType {
            get {
                if (element_type == null)
                    return typeof (JsonData);

                return element_type;
            }

            set { element_type = value; }
        }

        public bool IsDictionary {
            get { return is_dictionary; }
            set { is_dictionary = value; }
        }

        public IDictionary<string, PropertyMetadata> Properties {
            get { return properties; }
            set { properties = value; }
        }
    }


    internal delegate void ExporterFunc    (object obj, JsonWriter writer);
    public   delegate void ExporterFunc<T> (T obj, JsonWriter writer);

    internal delegate object ImporterFunc                (object input);
    public   delegate TValue ImporterFunc<TJson, TValue> (TJson input);

    public delegate IJsonWrapper WrapperFactory ();


    public class JsonMapper
    {
        #region Fields
        private static int max_nesting_depth;

        private static IFormatProvider datetime_format;

        private static IDictionary<Type, ExporterFunc> base_exporters_table;
        private static IDictionary<Type, ExporterFunc> custom_exporters_table;

        private static IDictionary<Type,
                IDictionary<Type, ImporterFunc>> base_importers_table;
        private static IDictionary<Type,
                IDictionary<Type, ImporterFunc>> custom_importers_table;

        private static IDictionary<Type, ArrayMetadata> array_metadata;
        private static readonly object array_metadata_lock = new Object ();

        private static IDictionary<Type,
                IDictionary<Type, MethodInfo>> conv_ops;
        private static readonly object conv_ops_lock = new Object ();

        private static IDictionary<Type, ObjectMetadata> object_metadata;
        private static readonly object object_metadata_lock = new Object ();

        private static IDictionary<Type,
                IList<PropertyMetadata>> type_properties;
        private static readonly object type_properties_lock = new Object ();

        private static JsonWriter      static_writer;
        private static readonly object static_writer_lock = new Object ();
        #endregion


        #region Constructors
        static JsonMapper ()
        {
            max_nesting_depth = 100;

            array_metadata = new Dictionary<Type, ArrayMetadata> ();
            conv_ops = new Dictionary<Type, IDictionary<Type, MethodInfo>> ();
            object_metadata = new Dictionary<Type, ObjectMetadata> ();
            type_properties = new Dictionary<Type,
                            IList<PropertyMetadata>> ();

            static_writer = new JsonWriter ();

            datetime_format = DateTimeFormatInfo.InvariantInfo;

            base_exporters_table   = new Dictionary<Type, ExporterFunc> ();
            custom_exporters_table = new Dictionary<Type, ExporterFunc> ();

            base_importers_table = new Dictionary<Type,
                                 IDictionary<Type, ImporterFunc>> ();
            custom_importers_table = new Dictionary<Type,
                                   IDictionary<Type, ImporterFunc>> ();

            RegisterBaseExporters ();
            RegisterBaseImporters ();
        }
        #endregion


        #region Private Methods
        private static void AddArrayMetadata (Type type)
        {
            if (array_metadata.ContainsKey (type))
                return;

            ArrayMetadata data = new ArrayMetadata ();

            data.IsArray = type.IsArray;

            if (type.GetInterface ("System.Collections.IList") != null)
                data.IsList = true;

            if (type is ILRuntime.Reflection.ILRuntimeWrapperType)
            {
                var wt = (ILRuntime.Reflection.ILRuntimeWrapperType)type;
                if (data.IsArray)
                {
                    data.ElementType = wt.CLRType.ElementType.ReflectionType; 
                }
                else
                {
                    data.ElementType = wt.CLRType.GenericArguments[0].Value.ReflectionType;
                }
            }
            else
            {
                foreach (PropertyInfo p_info in type.GetProperties())
                {
                    if (p_info.Name != "Item")
                        continue;

                    ParameterInfo[] parameters = p_info.GetIndexParameters();

                    if (parameters.Length != 1)
                        continue;

                    if (parameters[0].ParameterType == typeof(int))
                        data.ElementType = p_info.PropertyType;
                }
            }
            lock (array_metadata_lock) {
                try {
                    array_metadata.Add (type, data);
                } catch (ArgumentException) {
                    return;
                }
            }
        }

        private static void AddObjectMetadata (Type type)
        {
            if (object_metadata.ContainsKey (type))
                return;

            ObjectMetadata data = new ObjectMetadata ();

            if (type.GetInterface ("System.Collections.IDictionary") != null)
                data.IsDictionary = true;

            data.Properties = new Dictionary<string, PropertyMetadata> ();
            foreach (PropertyInfo p_info in type.GetProperties ()) {
                if (p_info.Name == "Item") {
                    ParameterInfo[] parameters = p_info.GetIndexParameters ();

                    if (parameters.Length != 1)
                        continue;

                    if (parameters[0].ParameterType == typeof(string))
                    {
                        if (type is ILRuntime.Reflection.ILRuntimeWrapperType)
                        {
                            data.ElementType = ((ILRuntime.Reflection.ILRuntimeWrapperType)type).CLRType.GenericArguments[1].Value.ReflectionType;
                        }
                        else
                            data.ElementType = p_info.PropertyType;
                    }

                    continue;
                }

                PropertyMetadata p_data = new PropertyMetadata ();
                p_data.Info = p_info;
                p_data.Type = p_info.PropertyType;

                data.Properties.Add (p_info.Name, p_data);
            }

            foreach (FieldInfo f_info in type.GetFields ()) {
                PropertyMetadata p_data = new PropertyMetadata ();
                p_data.Info = f_info;
                p_data.IsField = true;
                p_data.Type = f_info.FieldType;

                data.Properties.Add (f_info.Name, p_data);
            }

            lock (object_metadata_lock) {
                try {
                    object_metadata.Add (type, data);
                } catch (ArgumentException) {
                    return;
                }
            }
        }

        private static void AddTypeProperties (Type type)
        {
            if (type_properties.ContainsKey (type))
                return;

            IList<PropertyMetadata> props = new List<PropertyMetadata> ();

            foreach (PropertyInfo p_info in type.GetProperties ()) {
                if (p_info.Name == "Item")
                    continue;

                PropertyMetadata p_data = new PropertyMetadata ();
                p_data.Info = p_info;
                p_data.IsField = false;
                props.Add (p_data);
            }

            foreach (FieldInfo f_info in type.GetFields ()) {
                PropertyMetadata p_data = new PropertyMetadata ();
                p_data.Info = f_info;
                p_data.IsField = true;

                props.Add (p_data);
            }

            lock (type_properties_lock) {
                try {
                    type_properties.Add (type, props);
                } catch (ArgumentException) {
                    return;
                }
            }
        }

        private static MethodInfo GetConvOp (Type t1, Type t2)
        {
            lock (conv_ops_lock) {
                if (! conv_ops.ContainsKey (t1))
                    conv_ops.Add (t1, new Dictionary<Type, MethodInfo> ());
            }

            if (conv_ops[t1].ContainsKey (t2))
                return conv_ops[t1][t2];

            MethodInfo op = t1.GetMethod (
                "op_Implicit", new Type[] { t2 });

            lock (conv_ops_lock) {
                try {
                    conv_ops[t1].Add (t2, op);
                } catch (ArgumentException) {
                    return conv_ops[t1][t2];
                }
            }

            return op;
        }

        private static object ReadValue (Type inst_type, JsonReader reader)
        {
            reader.Read ();

            if (reader.Token == JsonToken.ArrayEnd)
                return null;

            //ILRuntime doesn't support nullable valuetype
            Type underlying_type = inst_type;//Nullable.GetUnderlyingType(inst_type);
            Type value_type = inst_type;

            if (reader.Token == JsonToken.Null) {
                if (inst_type.IsClass || underlying_type != null) {
                    return null;
                }

                throw new JsonException (String.Format (
                            "Can't assign null to an instance of type {0}",
                            inst_type));
            }

            if (reader.Token == JsonToken.Double ||
                reader.Token == JsonToken.Int ||
                reader.Token == JsonToken.Long ||
                reader.Token == JsonToken.String ||
                reader.Token == JsonToken.Boolean) {

                Type json_type = reader.Value.GetType();
                var vt = value_type is ILRuntime.Reflection.ILRuntimeWrapperType ? ((ILRuntime.Reflection.ILRuntimeWrapperType)value_type).CLRType.TypeForCLR : value_type;

                if (vt.IsAssignableFrom(json_type))
                    return reader.Value;
                if (vt is ILRuntime.Reflection.ILRuntimeType && ((ILRuntime.Reflection.ILRuntimeType)vt).ILType.IsEnum)
                {
                    if (json_type == typeof(int) || json_type == typeof(long) || json_type == typeof(short) || json_type == typeof(byte))
                        return reader.Value;
                }
                // If there's a custom importer that fits, use it
                if (custom_importers_table.ContainsKey (json_type) &&
                    custom_importers_table[json_type].ContainsKey (
                        vt)) {

                    ImporterFunc importer =
                        custom_importers_table[json_type][vt];

                    return importer (reader.Value);
                }

                // Maybe there's a base importer that works
                if (base_importers_table.ContainsKey (json_type) &&
                    base_importers_table[json_type].ContainsKey (
                        vt)) {

                    ImporterFunc importer =
                        base_importers_table[json_type][vt];

                    return importer (reader.Value);
                }

                // Maybe it's an enum
                if (vt.IsEnum)
                    return Enum.ToObject (vt, reader.Value);

                // Try using an implicit conversion operator
                MethodInfo conv_op = GetConvOp (vt, json_type);

                if (conv_op != null)
                    return conv_op.Invoke (null,
                                           new object[] { reader.Value });

                // No luck
                throw new JsonException (String.Format (
                        "Can't assign value '{0}' (type {1}) to type {2}",
                        reader.Value, json_type, inst_type));
            }

            object instance = null;

            if (reader.Token == JsonToken.ArrayStart) {

                AddArrayMetadata (inst_type);
                ArrayMetadata t_data = array_metadata[inst_type];

                if (! t_data.IsArray && ! t_data.IsList)
                    throw new JsonException (String.Format (
                            "Type {0} can't act as an array",
                            inst_type));

                IList list;
                Type elem_type;

                if (! t_data.IsArray) {
                    list = (IList) Activator.CreateInstance (inst_type);
                    elem_type = t_data.ElementType;
                } else {
                    list = new ArrayList ();
                    elem_type = inst_type.GetElementType ();
                }

                while (true) {
                    object item = ReadValue (elem_type, reader);
                    if (item == null && reader.Token == JsonToken.ArrayEnd)
                        break;
                    var rt = elem_type is ILRuntime.Reflection.ILRuntimeWrapperType ? ((ILRuntime.Reflection.ILRuntimeWrapperType)elem_type).RealType : elem_type;
                    item = rt.CheckCLRTypes(item);
                    list.Add (item);
                }

                if (t_data.IsArray) {
                    int n = list.Count;
                    instance = Array.CreateInstance (elem_type, n);

                    for (int i = 0; i < n; i++)
                        ((Array) instance).SetValue (list[i], i);
                } else
                    instance = list;

            } else if (reader.Token == JsonToken.ObjectStart) {
                AddObjectMetadata (value_type);
                ObjectMetadata t_data = object_metadata[value_type];
                if (value_type is ILRuntime.Reflection.ILRuntimeType)
                    instance = ((ILRuntime.Reflection.ILRuntimeType)value_type).ILType.Instantiate();
                else
                {
                    if (value_type is ILRuntime.Reflection.ILRuntimeWrapperType)
                        value_type = ((ILRuntime.Reflection.ILRuntimeWrapperType)value_type).RealType;
                    instance = Activator.CreateInstance(value_type);
                }
                while (true) {
                    reader.Read ();

                    if (reader.Token == JsonToken.ObjectEnd)
                        break;

                    string property = (string) reader.Value;

                    if (t_data.Properties.ContainsKey (property)) {
                        PropertyMetadata prop_data =
                            t_data.Properties[property];

                        if (prop_data.IsField) {
                            ((FieldInfo) prop_data.Info).SetValue (
                                instance, ReadValue (prop_data.Type, reader));
                        } else {
                            PropertyInfo p_info =
                                (PropertyInfo) prop_data.Info;

                            if (p_info.CanWrite)
                                p_info.SetValue (
                                    instance,
                                    ReadValue (prop_data.Type, reader),
                                    null);
                            else
                                ReadValue (prop_data.Type, reader);
                        }

                    } else {
                        if (! t_data.IsDictionary) {

                            if (! reader.SkipNonMembers) {
                                throw new JsonException (String.Format (
                                        "The type {0} doesn't have the " +
                                        "property '{1}'",
                                        inst_type, property));
                            } else {
                                ReadSkip (reader);
                                continue;
                            }
                        }

                        var rt = t_data.ElementType is ILRuntime.Reflection.ILRuntimeWrapperType ? ((ILRuntime.Reflection.ILRuntimeWrapperType)t_data.ElementType).RealType : t_data.ElementType;
                        ((IDictionary) instance).Add (
                            property, rt.CheckCLRTypes(ReadValue (
                                t_data.ElementType, reader)));
                    }

                }

            }

            return instance;
        }

        private static IJsonWrapper ReadValue (WrapperFactory factory,
                                               JsonReader reader)
        {
            reader.Read ();

            if (reader.Token == JsonToken.ArrayEnd ||
                reader.Token == JsonToken.Null)
                return null;

            IJsonWrapper instance = factory ();

            if (reader.Token == JsonToken.String) {
                instance.SetString ((string) reader.Value);
                return instance;
            }

            if (reader.Token == JsonToken.Double) {
                instance.SetDouble ((double) reader.Value);
                return instance;
            }

            if (reader.Token == JsonToken.Int) {
                instance.SetInt ((int) reader.Value);
                return instance;
            }

            if (reader.Token == JsonToken.Long) {
                instance.SetLong ((long) reader.Value);
                return instance;
            }

            if (reader.Token == JsonToken.Boolean) {
                instance.SetBoolean ((bool) reader.Value);
                return instance;
            }

            if (reader.Token == JsonToken.ArrayStart) {
                instance.SetJsonType (JsonType.Array);

                while (true) {
                    IJsonWrapper item = ReadValue (factory, reader);
                    if (item == null && reader.Token == JsonToken.ArrayEnd)
                        break;

                    ((IList) instance).Add (item);
                }
            }
            else if (reader.Token == JsonToken.ObjectStart) {
                instance.SetJsonType (JsonType.Object);

                while (true) {
                    reader.Read ();

                    if (reader.Token == JsonToken.ObjectEnd)
                        break;

                    string property = (string) reader.Value;

                    ((IDictionary) instance)[property] = ReadValue (
                        factory, reader);
                }

            }

            return instance;
        }

        private static void ReadSkip (JsonReader reader)
        {
            ToWrapper (
                delegate { return new JsonMockWrapper (); }, reader);
        }

        private static void RegisterBaseExporters ()
        {
            base_exporters_table[typeof (byte)] =
                delegate (object obj, JsonWriter writer) {
                    writer.Write (Convert.ToInt32 ((byte) obj));
                };

            base_exporters_table[typeof (char)] =
                delegate (object obj, JsonWriter writer) {
                    writer.Write (Convert.ToString ((char) obj));
                };

            base_exporters_table[typeof (DateTime)] =
                delegate (object obj, JsonWriter writer) {
                    writer.Write (Convert.ToString ((DateTime) obj,
                                                    datetime_format));
                };

            base_exporters_table[typeof (decimal)] =
                delegate (object obj, JsonWriter writer) {
                    writer.Write ((decimal) obj);
                };

            #region  litjson support float  modified by codingriver wangguoqing 2018-10-29
            base_exporters_table[typeof(float)] =
                delegate (object obj, JsonWriter writer) {
                    writer.Write((float)obj);
                };
            #endregion

            base_exporters_table[typeof (sbyte)] =
                delegate (object obj, JsonWriter writer) {
                    writer.Write (Convert.ToInt32 ((sbyte) obj));
                };

            base_exporters_table[typeof (short)] =
                delegate (object obj, JsonWriter writer) {
                    writer.Write (Convert.ToInt32 ((short) obj));
                };

            base_exporters_table[typeof (ushort)] =
                delegate (object obj, JsonWriter writer) {
                    writer.Write (Convert.ToInt32 ((ushort) obj));
                };

            base_exporters_table[typeof (uint)] =
                delegate (object obj, JsonWriter writer) {
                    writer.Write (Convert.ToUInt64 ((uint) obj));
                };

            base_exporters_table[typeof (ulong)] =
                delegate (object obj, JsonWriter writer) {
                    writer.Write ((ulong) obj);
                };
        }

        private static void RegisterBaseImporters ()
        {
            ImporterFunc importer;

            importer = delegate (object input) {
                return Convert.ToByte ((int) input);
            };
            RegisterImporter (base_importers_table, typeof (int),
                              typeof (byte), importer);

            importer = delegate (object input) {
                return Convert.ToUInt64 ((int) input);
            };
            RegisterImporter (base_importers_table, typeof (int),
                              typeof (ulong), importer);

            importer = delegate (object input) {
                return Convert.ToSByte ((int) input);
            };
            RegisterImporter (base_importers_table, typeof (int),
                              typeof (sbyte), importer);

            importer = delegate (object input) {
                return Convert.ToInt16 ((int) input);
            };
            RegisterImporter (base_importers_table, typeof (int),
                              typeof (short), importer);

            importer = delegate (object input) {
                return Convert.ToInt64((int)input);
            };
            RegisterImporter(base_importers_table, typeof(int),
                              typeof(long), importer);

            importer = delegate (object input) {
                return Convert.ToUInt16 ((int) input);
            };
            RegisterImporter (base_importers_table, typeof (int),
                              typeof (ushort), importer);

            importer = delegate (object input) {
                return Convert.ToUInt32 ((int) input);
            };
            RegisterImporter (base_importers_table, typeof (int),
                              typeof (uint), importer);

            importer = delegate (object input) {
                return Convert.ToSingle ((int) input);
            };
            RegisterImporter (base_importers_table, typeof (int),
                              typeof (float), importer);

            importer = delegate (object input) {
                return Convert.ToDouble ((int) input);
            };
            RegisterImporter (base_importers_table, typeof (int),
                              typeof (double), importer);

            importer = delegate (object input) {
                return Convert.ToDecimal ((double) input);
            };
            RegisterImporter (base_importers_table, typeof (double),
                              typeof (decimal), importer);

            #region  litjson support float  modified by codingriver  2018-10-29
            importer = delegate (object input) {
                return Convert.ToSingle((double)input);
            };

            RegisterImporter(base_importers_table, typeof(double),
                               typeof(float), importer);
            #endregion

            importer = delegate (object input) {
                return Convert.ToUInt32 ((long) input);
            };
            RegisterImporter (base_importers_table, typeof (long),
                              typeof (uint), importer);

            importer = delegate (object input) {
                return Convert.ToChar ((string) input);
            };
            RegisterImporter (base_importers_table, typeof (string),
                              typeof (char), importer);

            importer = delegate (object input) {
                return Convert.ToDateTime ((string) input, datetime_format);
            };
            RegisterImporter (base_importers_table, typeof (string),
                              typeof (DateTime), importer);
        }

        private static void RegisterImporter (
            IDictionary<Type, IDictionary<Type, ImporterFunc>> table,
            Type json_type, Type value_type, ImporterFunc importer)
        {
            if (! table.ContainsKey (json_type))
                table.Add (json_type, new Dictionary<Type, ImporterFunc> ());

            table[json_type][value_type] = importer;
        }

        private static void WriteValue (object obj, JsonWriter writer,
                                        bool writer_is_private,
                                        int depth)
        {
            if (depth > max_nesting_depth)
                throw new JsonException (
                    String.Format ("Max allowed object depth reached while " +
                                   "trying to export from type {0}",
                                   obj.GetType ()));

            if (obj == null) {
                writer.Write (null);
                return;
            }

            if (obj is IJsonWrapper) {
                if (writer_is_private)
                    writer.TextWriter.Write (((IJsonWrapper) obj).ToJson ());
                else
                    ((IJsonWrapper) obj).ToJson (writer);

                return;
            }

            if (obj is String) {
                writer.Write ((string) obj);
                return;
            }

            if (obj is Double) {
                writer.Write ((double) obj);
                return;
            }

            if (obj is Int32) {
                writer.Write ((int) obj);
                return;
            }

            if (obj is Boolean) {
                writer.Write ((bool) obj);
                return;
            }

            if (obj is Int64) {
                writer.Write ((long) obj);
                return;
            }

            if (obj is Array) {
                writer.WriteArrayStart ();

                foreach (object elem in (Array) obj)
                    WriteValue (elem, writer, writer_is_private, depth + 1);

                writer.WriteArrayEnd ();

                return;
            }

            if (obj is IList) {
                writer.WriteArrayStart ();
                foreach (object elem in (IList) obj)
                    WriteValue (elem, writer, writer_is_private, depth + 1);
                writer.WriteArrayEnd ();

                return;
            }

            if (obj is IDictionary) {
                writer.WriteObjectStart ();
                foreach (DictionaryEntry entry in (IDictionary) obj) {
                    writer.WritePropertyName ((string) entry.Key);
                    WriteValue (entry.Value, writer, writer_is_private,
                                depth + 1);
                }
                writer.WriteObjectEnd ();

                return;
            }

            Type obj_type;
            if (obj is ILRuntime.Runtime.Intepreter.ILTypeInstance)
            {
                obj_type = ((ILRuntime.Runtime.Intepreter.ILTypeInstance)obj).Type.ReflectionType;
            }
            else if(obj is ILRuntime.Runtime.Enviorment.CrossBindingAdaptorType)
            {
                obj_type = ((ILRuntime.Runtime.Enviorment.CrossBindingAdaptorType)obj).ILInstance.Type.ReflectionType;
            }
            else
                obj_type = obj.GetType();

            // See if there's a custom exporter for the object
            if (custom_exporters_table.ContainsKey (obj_type)) {
                ExporterFunc exporter = custom_exporters_table[obj_type];
                exporter (obj, writer);

                return;
            }

            // If not, maybe there's a base exporter
            if (base_exporters_table.ContainsKey (obj_type)) {
                ExporterFunc exporter = base_exporters_table[obj_type];
                exporter (obj, writer);

                return;
            }

            // Last option, let's see if it's an enum
            if (obj is Enum) {
                Type e_type = Enum.GetUnderlyingType (obj_type);

                if (e_type == typeof (long)
                    || e_type == typeof (uint)
                    || e_type == typeof (ulong))
                    writer.Write ((ulong) obj);
                else
                    writer.Write ((int) obj);

                return;
            }

            // Okay, so it looks like the input should be exported as an
            // object
            AddTypeProperties (obj_type);
            IList<PropertyMetadata> props = type_properties[obj_type];

            writer.WriteObjectStart ();
            foreach (PropertyMetadata p_data in props) {
                if (p_data.IsField) {
                    writer.WritePropertyName (p_data.Info.Name);
                    WriteValue (((FieldInfo) p_data.Info).GetValue (obj),
                                writer, writer_is_private, depth + 1);
                }
                else {
                    PropertyInfo p_info = (PropertyInfo) p_data.Info;

                    if (p_info.CanRead) {
                        writer.WritePropertyName (p_data.Info.Name);
                        WriteValue (p_info.GetValue (obj, null),
                                    writer, writer_is_private, depth + 1);
                    }
                }
            }
            writer.WriteObjectEnd ();
        }
        #endregion


        public static string ToJson (object obj)
        {
            lock (static_writer_lock) {
                static_writer.Reset ();

                WriteValue (obj, static_writer, true, 0);

                return static_writer.ToString ();
            }
        }

        public static void ToJson (object obj, JsonWriter writer)
        {
            WriteValue (obj, writer, false, 0);
        }

        public static JsonData ToObject (JsonReader reader)
        {
            return (JsonData) ToWrapper (
                delegate { return new JsonData (); }, reader);
        }

        public static JsonData ToObject (TextReader reader)
        {
            JsonReader json_reader = new JsonReader (reader);

            return (JsonData) ToWrapper (
                delegate { return new JsonData (); }, json_reader);
        }

        public static JsonData ToObject (string json)
        {
            return (JsonData) ToWrapper (
                delegate { return new JsonData (); }, json);
        }

        public static T ToObject<T> (JsonReader reader)
        {
            return (T) ReadValue (typeof (T), reader);
        }

        public static T ToObject<T> (TextReader reader)
        {
            JsonReader json_reader = new JsonReader (reader);

            return (T) ReadValue (typeof (T), json_reader);
        }

        public static T ToObject<T> (string json)
        {
            JsonReader reader = new JsonReader (json);

            return (T) ReadValue (typeof (T), reader);
        }

	    public static object ToObject(Type type, string json)
	    {
		    JsonReader reader = new JsonReader(json);
			return ReadValue(type, reader);
	    }

		public static IJsonWrapper ToWrapper (WrapperFactory factory,
                                              JsonReader reader)
        {
            return ReadValue (factory, reader);
        }

        public static IJsonWrapper ToWrapper (WrapperFactory factory,
                                              string json)
        {
            JsonReader reader = new JsonReader (json);

            return ReadValue (factory, reader);
        }

        public static void RegisterExporter<T> (ExporterFunc<T> exporter)
        {
            ExporterFunc exporter_wrapper =
                delegate (object obj, JsonWriter writer) {
                    exporter ((T) obj, writer);
                };

            custom_exporters_table[typeof (T)] = exporter_wrapper;
        }

        public static void RegisterImporter<TJson, TValue> (
            ImporterFunc<TJson, TValue> importer)
        {
            ImporterFunc importer_wrapper =
                delegate (object input) {
                    return importer ((TJson) input);
                };

            RegisterImporter (custom_importers_table, typeof (TJson),
                              typeof (TValue), importer_wrapper);
        }

        public static void UnregisterExporters ()
        {
            custom_exporters_table.Clear ();
        }

        public static void UnregisterImporters ()
        {
            custom_importers_table.Clear ();
        }

        public unsafe static void RegisterILRuntimeCLRRedirection(ILRuntime.Runtime.Enviorment.AppDomain appdomain)
        {
            foreach(var i in typeof(JsonMapper).GetMethods())
            {
                if(i.Name == "ToObject" && i.IsGenericMethodDefinition)
                {
                    var param = i.GetParameters();
                    if(param[0].ParameterType == typeof(string))
                    {
                        appdomain.RegisterCLRMethodRedirection(i, JsonToObject);
                    }
                    else if(param[0].ParameterType == typeof(JsonReader))
                    {
                        appdomain.RegisterCLRMethodRedirection(i, JsonToObject2);
                    }
                    else if (param[0].ParameterType == typeof(TextReader))
                    {
                        appdomain.RegisterCLRMethodRedirection(i, JsonToObject3);
                    }
                }
            }
        }

        public unsafe static StackObject* JsonToObject(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
        {
            ILRuntime.Runtime.Enviorment.AppDomain __domain = intp.AppDomain;
            StackObject* ptr_of_this_method;
            StackObject* __ret = ILIntepreter.Minus(esp, 1);
            ptr_of_this_method = ILIntepreter.Minus(esp, 1);
            System.String json = (System.String)typeof(System.String).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, mStack));
            intp.Free(ptr_of_this_method);
            var type = method.GenericArguments[0].ReflectionType;
            var result_of_this_method = ReadValue(type, new JsonReader(json));

            return ILIntepreter.PushObject(__ret, mStack, result_of_this_method);
        }

        public unsafe static StackObject* JsonToObject2(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
        {
            ILRuntime.Runtime.Enviorment.AppDomain __domain = intp.AppDomain;
            StackObject* ptr_of_this_method;
            StackObject* __ret = ILIntepreter.Minus(esp, 1);
            ptr_of_this_method = ILIntepreter.Minus(esp, 1);
            JsonReader json = (JsonReader)typeof(JsonReader).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, mStack));
            intp.Free(ptr_of_this_method);
            var type = method.GenericArguments[0].ReflectionType;
            var result_of_this_method = ReadValue(type, json);

            return ILIntepreter.PushObject(__ret, mStack, result_of_this_method);
        }

        public unsafe static StackObject* JsonToObject3(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
        {
            ILRuntime.Runtime.Enviorment.AppDomain __domain = intp.AppDomain;
            StackObject* ptr_of_this_method;
            StackObject* __ret = ILIntepreter.Minus(esp, 1);
            ptr_of_this_method = ILIntepreter.Minus(esp, 1);
            TextReader json = (TextReader)typeof(TextReader).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, mStack));
            intp.Free(ptr_of_this_method);
            var type = method.GenericArguments[0].ReflectionType;
            var result_of_this_method = ReadValue(type, new JsonReader(json));

            return ILIntepreter.PushObject(__ret, mStack, result_of_this_method);
        }
    }
}

<think>我们遇到了一个类型转换错误:`Unable to cast System.Single to System.Double`。这个错误发生在尝试为NumericUpDown控件的Value属性设置一个Single类型(即float)的值时,而该属性期望的是Double类型(在WPF中可能是decimal或double,具体取决于控件)。在.NET中,NumericUpDown控件(无论是Windows Forms还是WPF)的Value属性通常是decimal类型(Windows Forms)或double类型(WPF)。但是,错误信息明确指出尝试将Single转换为Double,这表明我们可能在使用WPF的NumericUpDown(因为它的Valuedouble类型),并且我们试图将一个floatSingle)值赋给它,而.NET不允许隐式转换floatdouble?实际上,在C#中,float可以隐式转换为double,所以这个错误可能另有原因。 然而,错误信息是“Unable to cast System.Single to System.Double”,这通常意味着我们尝试使用强制转换(cast)将Single转换为Double,但转换失败。但实际上,在C#中,floatSingle)可以隐式转换为doubleDouble),所以通常不会出现InvalidCastException。因此,这个错误可能发生在其他场景,比如在据绑定或反射时。 但是,根据用户提供的引用[1]中提到的错误:`Unable to cast object of type 'System.Int32' to type 'System.Array'`,这是一个InvalidCastException,通常发生在尝试将一个非组对象强制转换为类型时。同样,用户现在遇到的错误是尝试将Singlefloat)转换为Doubledouble)时出现InvalidCastException,这同样是不合理的,因为float可以隐式转double。所以,我们可能需要考虑以下情况: 1. 据绑定上下文:可能是在据绑定中,源属性是float类型,而目标属性(NumericUpDown.Value)是double类型,但绑定引擎在转换时出错。 2. 使用反射设置属性:可能通过反射设置Value属性,而反射要求类型完全匹配或可转换,但可能由于某种原因转换失败。 3. 控件内部实现:可能是控件内部在处理值时进行了某种转换,而该转换不支持。 但是,用户提到错误发生在“设置控件值时”,所以可能是直接赋值或通过绑定赋值。 **重新分析问题**:用户说“设置值时控件报错”,并提到之前的错误是关于NumericUpDownValue的,现在又提到类型转换错误System.InvalidCastException: 无法将System.Single转换为System.Double)。所以,我们可能需要关注赋值时的类型。 在Windows Forms中,NumericUpDown控件的Value属性是decimal类型。在WPF中,如果使用扩展工具包(如Extended WPF Toolkit)中的NumericUpDown控件,它的Value属性是double类型。因此,如果我们尝试将一个float值赋给一个decimal属性(Windows Forms)或double属性(WPF),按理说C#会进行隐式转换(floatdouble可以隐式转换,但float到decimal不能隐式转换,需要显式转换)。所以,如果是在Windows Forms中,我们试图将float赋值给decimal,则编译器会报错(编译时错误),而不是运行时InvalidCastException。但是,如果通过反射赋值,则可能会在运行时抛出InvalidCastException。 因此,我们假设用户使用的是WPF的NumericUpDown(因为Valuedouble),并且通过某种方式(可能是反射或据绑定)设置值,而该方式要求显式转换。 **解决方案**: 1. **显式转换**:在赋值前,将float显式转换为double(尽管隐式转换通常可行,但为了清晰和避免反射问题,可以显式转换)。 2. **检查赋值方式**:如果直接赋值,确保类型正确。如果通过据绑定,检查绑定转换器。 3. **使用转换器**:在据绑定时,如果源类型和目标类型不匹配,可以使用值转换器(IValueConverter)。 ### 详细步骤 #### 情况1:直接代码赋值 如果是在代码中直接设置控件的Value,并且确定控件是WPF的NumericUpDown(Valuedouble),那么可以这样: ```csharp float myValue = 68.57f; // 假设有一个float值 numericUpDown1.Value = (double)myValue; // 显式转换为double ``` 或者,由于floatdouble是隐式的,也可以直接赋值: ```csharp numericUpDown1.Value = myValue; // 隐式转换 ``` 但为什么会出现InvalidCastException呢?可能是因为在赋值过程中,值被装箱后再拆箱到double,而拆箱要求类型完全匹配。例如: ```csharp object boxedValue = myValue; // 装箱为float // 然后尝试拆箱为double double unboxedValue = (double)boxedValue; // 这里会抛出InvalidCastException,因为拆箱必须到相同的类型 ``` 所以,如果赋值过程中有装箱拆箱操作(比如通过反射或非泛型集合),则会出现此问题。 #### 情况2:通过反射设置属性 如果使用反射设置属性,则必须确保类型匹配。例如: ```csharp var propertyInfo = numericUpDown1.GetType().GetProperty("Value"); float myValue = 68.57f; // 下面这行会抛出InvalidCastException,因为反射的SetValue方法要求提供的值类型与属性类型完全匹配或可转换,但floatdouble的转换在反射中可能不被支持 propertyInfo.SetValue(numericUpDown1, myValue); ``` 解决方法:在反射赋值前,将值转换为目标类型: ```csharp propertyInfo.SetValue(numericUpDown1, (double)myValue); ``` #### 情况3:据绑定 如果使用据绑定,则可以在绑定中使用转换器: XAML: ```xml <Window.Resources> <local:FloatToDoubleConverter x:Key="FloatToDoubleConverter"/> </Window.Resources> ... <extended:NumericUpDown Value="{Binding MyFloatValue, Converter={StaticResource FloatToDoubleConverter}}" /> ``` 转换器实现: ```csharp public class FloatToDoubleConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { // 从源到目标:float -> double if (value is float) { return (double)(float)value; } return value; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { // 从目标到源:double -> float if (value is double) { return (float)(double)value; } return value; } } ``` ### 总结 - **根本原因**:在设置NumericUpDown的Value属性时,传入的值是System.Singlefloat),但属性期望的是System.Doubledouble)。在直接赋值时,C#会进行隐式转换,但若赋值过程中涉及装箱拆箱(如反射、集合等)则会导致InvalidCastException。 - **解决方法**: 1. 在赋值前显式将float转换为double。 2. 如果通过反射赋值,确保传入转换后的double值。 3. 如果使用据绑定,使用转换器进行类型转换。 ### 注意事项 - 在Windows Forms中,NumericUpDown的Value是decimal类型,因此不能直接赋值float,必须先转换为decimal(但转换可能损失精度)。例如: ```csharp float myValue = 68.57f; numericUpDown1.Value = (decimal)myValue; // 显式转换为decimal ``` 注意:float到decimal的转换可能会导致精度损失,因为float的精度较低。 ### 相关问题 1. 如何在WPF中正确使用NumericUpDown控件? 2. 据绑定中类型不匹配的常见解决方法有哪些? 3..NET中,值类型之间的转换规则是什么?</think>### 解决 "Unable to cast System.Single to System.Double" 类型转换错误 您在设置 NumericUpDown 控件值时遇到的 `System.InvalidCastException` 错误,本质上是由于 .NET 类型系统无法直接将单精度浮点Single/float)转换为双精度浮点Double),尤其是在控件属性要求特定类型时发生。结合引用[1]和[2]的信息,以下是深度分析和解决方案: --- #### 问题根源分析 1. **类型系统不匹配**: - `System.Single` (float, 32位) 和 `System.Double` (double, 64位) 是两种不同的浮点类型 - NumericUpDown 的 `Value` 属性通常要求 `decimal` 或 `double` 类型(取决于控件实现) - 直接赋值时,.NET 不会自动在浮点类型间转换,导致 `InvalidCastException`[^1] 2. **精度差异引发的陷阱**: - 如引用[2]所述,浮点类型转换易丢失精度(如 `68.56999969482422`) - 控件内部可能使用 `decimal` 类型存储值(精确十进制),而您的据源是 `float`[^2] 3. **常见触发场景**: ```csharp float externalValue = 68.57f; // 来自外部据源 numericUpDown.Value = externalValue; // 抛出 InvalidCastException ``` --- #### 解决方案(分步骤实现) ##### 方法1:显式类型转换(推荐) ```csharp float sourceValue = GetFloatValue(); // 从据源获取 float 值 // 方案1:转换为 double(适合 WPF 的 NumericUpDown) numericUpDown.Value = (double)sourceValue; // 方案2:转换为 decimal(适合 WinForms 的 NumericUpDown) numericUpDown.Value = (decimal)sourceValue; ``` ##### 方法2:使用 `Convert` 类(自动处理边界值) ```csharp float sourceValue = 68.57f; numericUpDown.Value = Convert.ToDecimal(sourceValue); // 自动转换 + 溢出检查 ``` ##### 方法3:据绑定时的类型转换器(WPF/MVVM 场景) ```csharp // 在 XAML 中绑定使用转换器 <nu:NumericUpDown Value="{Binding Path=FloatValue, Converter={StaticResource FloatToDoubleConverter}}"/> // 转换器实现 public class FloatToDoubleConverter : IValueConverter { public object Convert(object value, Type targetType, object p, CultureInfo c) { return System.Convert.ToDouble(value); // floatdouble } public object ConvertBack(...) { ... } } ``` ##### 方法4:全局处理浮点精度(解决如 68.56999969482422 的精度问题) ```csharp decimal SafeConvert(float value) { // 四舍五入到小点后4位,避免浮点误差 return (decimal)Math.Round(value, 4); } numericUpDown.Value = SafeConvert(68.56999969482422f); ``` --- #### 关键预防措施 1. **类型一致性检查**: ```csharp if (externalValue is float) { numericUpDown.Value = (decimal)(float)externalValue; } ``` 2. **控件初始化规范**: ```csharp numericUpDown.Minimum = 0m; // 明确使用 decimal 字面量 numericUpDown.Maximum = 100m; numericUpDown.DecimalPlaces = 4; // 显式设置小 ``` 3. **据源类型验证**: ```csharp var value = dataSource.GetValue(); if (value.GetType() != typeof(decimal)) { throw new InvalidOperationException("需要 decimal 类型据源"); } ``` --- #### 学原理说明 浮点转换的误差问题源于二进制表示差异: $$ \text{float} \rightarrow \text{double} : \quad x_{\text{float}} = x \pm \epsilon_{\text{float}} $$ $$ \text{转换后} : \quad x_{\text{double}} = x \pm \epsilon_{\text{float}} + \delta $$ 其中 $\delta$ 是二次转换误差。使用 `decimal` 可避免此问题,因其采用十进制表示法[^2]。 --- #### 相关问题 1. 如何正确处理 WinForms 和 WPF 中 NumericUpDown 控件的类型差异? 2.据库交互时如何避免浮点精度丢失问题? 3. 如何为 NumericUpDown 创建自定义类型安全包装器? 4. 为什么在 JSON 序列化中浮点容易丢失精度?如何解决?[^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值