C#使用泛型类和泛型方法解决"动态类型"问题

一、缘起   
最近做项目,碰到一个很有意思的问题,虽然不是很难,但是在网络上看到资料却很少,我想这或许又是另一个被容易忽略的话题。
问题是这样的:项目中用到一个类,他有一个保存数据的属性Value,这个属性有个比较奇怪的地方就是,他的类型,是无法预先估计的,会随着软件的扩展而变化,也就是我们常说的动态类型。

二、分析问题
   
这个问题解决方法很容易就可以看出有2种:
1、使用object基类
    使用这种方式能够解决问题,但是会引起装箱、拆箱等影响性能的低效操作,不可取;
2、使用泛型类
    使用泛型类也是能够解决问题的,但是在所有使用该对象时指出具体的类型,而这个会让上层使用该类时因具体类不同而不好组织,也不可取;
三、解决问题   
为了避免伤处麻烦,我采用了泛型类 + 泛型方法的模式来解决问题,简单的说,就是
1、把Value的类型抽象出来做成一个类,我们称他为DynamicValue,这个类含有DataType来存储Value的数据类型,并提供了泛型方法GetValue和SetValue来读写Value的值。
2、在从DynamicValue上,派生一个泛型类DynamicValue<T>,用来实际存储数据。

    使用这个方法的好处就是,避免了使用object会产生的装箱、拆箱动作,封装了泛型类的具体类型变化,更加容易管理和使用了。
四、具体实现看下面的代码:

/// <summary>
/// 动态数据类型
/// </summary>
public class DynamicValue
{
    public string DataType { get; protected set; }

    /// <summary>
    /// 获取值之泛型方法
    /// </summary>
    /// <typeparam name="T">值类型</typeparam>
    /// <returns>
    /// 值
    /// </returns>
    public T GetValue<T>()
    {
        if (DataType == typeof(T).ToString())
        {
            return ((DynamicValue<T>)this).Value;
        }
        return default(T);
    }

    /// <summary>
    /// 设置值之泛型方法
    /// </summary>
    /// <typeparam name="T">值类型</typeparam>
    /// <param name="value">待复制参数</param>
    /// <returns>
    /// false:设置失败
    /// true:设置成功
    /// </returns>
    public bool SetValue<T>(T value)
    {
        if (DataType == typeof(T).ToString())
        {
            ((DynamicValue<T>)this).Value = value;
            return true;
        }
        return false;
    }

}



/// <summary>
/// 动态数据类型之泛型类
/// </summary>
/// <typeparam name="T"></typeparam>
public class DynamicValue<T> : DynamicValue
{
    /// <summary>
    /// 保存值
    /// </summary>
    public T Value { get; set; }

    /// <summary>
    /// 构造函数
    /// </summary>
    public DynamicValue()
        : this(default(T))
    {
    }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="value"></param>
    public DynamicValue(T value)
    {
        Value = value;
        DataType = typeof(T).ToString();
    }
}

五、测试代码

class Program
{
    static void Main(string[] args)
    {
        DynamicValue data = new DynamicValue<float>(12.3f);
        Console.WriteLine("类型正确,返回应有的值");
        Console.WriteLine(data.GetValue<float>());
        Console.WriteLine("类型不匹配,返回default(T),即:值类型为0,引用类型为null");
        Console.WriteLine(data.GetValue<TestValue>());
        data = new DynamicValue<TestValue>(new TestValue());
        Console.WriteLine("类型不匹配,返回default(T),即:值类型为0,引用类型为null");
        Console.WriteLine(data.GetValue<float>());
        Console.WriteLine("类型正确,返回应有的值");
        Console.WriteLine(data.GetValue<TestValue>());
        Console.Write("Press any key to exit..");
        Console.ReadKey();
    }
}



class TestValue
{
    public int Value { get; set; }
    public override string ToString()
    {
        return "Value = " + Value.ToString();
    }
}
六、测试结果
类型正确,返回应有的值
12.3
类型不匹配,返回default(T),即:值类型为0,引用类型为null

类型不匹配,返回default(T),即:值类型为0,引用类型为null
0
类型正确,返回应有的值
Value = 0
Press any key to exit..

skyworld -
共有0个回答