博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

 

一、缘起    最近做项目,碰到一个很有意思的问题,虽然不是很难,但是在网络上看到资料却很少,我想这或许又是另一个被容易忽略的话题。
问题是这样的:项目中用到一个类,他有一个保存数据的属性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 { getprotected 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 { getset; }

    
/// <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 { getset; }

    
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..

七、附录1、代码下载(这个就不提供了,反正上文已经都给出了,想动手调试的朋友,就自己复制粘贴下吧);
2、本系列其他文章:
容易被忽略的细节(1):config文件的使用