在运行时更改动态对象类型

时间:2014-05-15 03:15:31

标签: c# dynamic runtime

我有以下界面:

public interface IDynamicData: IPersistent
{
    string Name { get; }
    DataType Type { get; set; }
    string InputFormat { get; set; }
    dynamic Value { get; }
    string DisplayValue { get; }
}

我有几个实现此接口的类,但我感兴趣的是这个:

public class DynamicInput : IDynamicData
{
    public string Name { get; private set; }
    private DataType _Type;
    public DataType Type
    {
        get { return _Type; }
        set
        {
            _Type = value;
            switch (Type)
            {
                case DataType.String:
                    Mapping = new StringMap();
                    break;
                case DataType.Numeric:
                    Mapping = new DoubleMap();
                    break;
                case DataType.DateTime:
                    Mapping = new DateTimeMap();
                    break;
                default:
                    Mapping = new StringMap();
                    break;
            }
        }
    }
    [Browsable(false)]
    public dynamic Value { get; private set; }
    [Browsable(false)]
    public string DisplayValue
    {
        get
        {
            return Value != null && (Type.Equals(DataType.DateTime) || Type.Equals(DataType.Numeric))
                ? Value.ToString(InputFormat)
                : Value;
        }
    }
}

现在,关键是dynamic Value属性。使用StringMapDecimalMapDoubleMapDateTimeMap类从字符串输入填充此值,其中键方法(类似于)此类:

public override dynamic ProcessInput(string input, int index, string inputFormat, double multiplier, char splitOn = ',')
    {
        _IsValid = false;
        try
        {
            _Input = input;
            double tmp;
            _IsValid = Double.TryParse(input.Split(splitOn)[index], out tmp);
            return tmp * multiplier;
        }
        catch
        {
            _IsValid = false;
            return 0;
        }
    }

这看起来很好用,我在运行时实际上有一个强类型Value属性(至少我理解它)。我想知道何时出现这种类型的定义 - 实例化对象时,或者Value被分配给。{/ p>

我希望能够让用户在运行时更改Value属性的类型,这涉及将DataType属性设置为string / DateTime / double等。但是,这有时会导致在运行时抛出RuntimeBindingException。它不会一直发生,只是有时候,我假设在DataType属性被设置的Value属性和正在读取的DisplayText属性之间发生变化时发生。这就是错误发生的地方,在这个getter中:

public string DisplayValue
    {
        get
        {
            return Value != null && (Type.Equals(DataType.DateTime) || Type.Equals(DataType.Numeric))
                ? Value.ToString(InputFormat)
                : Value;
        }
    }

我只想了解为什么会发生这种情况,以及我的分析是否正确,以及可能是否存在此问题的解决方法。如果它不可能那么没关系,我将锁定IDynamicData对象类型的编辑。

修改

我只经历了一次 - 难以复制。实例是,该对象是使用DataType.Numeric创建的。我输入了像“12.345”这样的字符串,每秒都被解析然后分配给Value属性。然后,当我仍在接收数据时,我改为DataType.String。这是异常发生的地方。也就是说,DoubleMap返回“动态”double,然后当输入数据仍然存在时,StringMap返回“动态”string表示“12.345”

1 个答案:

答案 0 :(得分:1)

我怀疑你有一个值,如字符串“15”,但Type属性设置为,例如,DataType.Numeric。在这种情况下,您的代码将尝试调用ToString()的参数化重载。因为接收对象是一个字符串,所以没有这样的重载,因此绑定器会抛出异常。

这有点推测。如果你可以发布一个演示问题的工作示例,或者至少描述抛出异常时使用的特定值,我们可以更确定它的原因。

如果要将数字的字符串表示形式转换为该数字的int或double表示形式,则需要转换Value属性中的实际值。 (顺便说一下,属性的实际类型是对象,因此这里存储的值路由将被装箱。)对此最好的解决方案在某种程度上取决于您希望调用代码的外观。

编辑以响应您的编辑:另一种可能性是Value对象是数字数据类型,例如double,但Type属性是DataType.String。在这种情况下,您的代码会尝试直接返回double,这会导致binder失败,就像

一样
string s = 1.2

会编译。在这种情况下,您可以使用ToString(),因此:

return Value != null && (Type.Equals(DataType.DateTime) || Type.Equals(DataType.Numeric))
            ? Value.ToString(InputFormat)
            : Value.ToString();

然而,这更像是一种解决方法,而不是一种解决方案。我会检查对象的运行时类型并删除Type属性。