2004年7月7日

展示C#模板的能力

其实C#模版的能力不强,一些代码便可以基本展示C#模版的能力。并且C#的模版就在也没有更多的能力了。最初接触C# 2.0的模版时,感到兴奋,没多少天就觉得其能力还是很受限的。可能这也体现了简单易用的一个原则吧,毕竟C#是一个大众化的语言!

 //不同于C++,需要使用template<class T, class V>
 
//或者template<typename T, typename V>声明模板参数
 public class A<T, V>
 
{
       
public static int I = 0;
 }


 
//部分实例化
 public class A<T> : A<T, object>
 
{
       
public static new int I = A<T, object>.I + 1;
 }


 
//部分实例化,约束T必须实现接口ICollection<T>
 public class C<T> : A<T, string> where T : ICollection<T>
 
{
 }


 
public class D
 
{
       
//模板化的方法,约束T必须有缺省构造函数
       public T F<T>() where T : new()
       
{
             
return new T();
       }

 }

posted @ 2004-07-07 22:45 温少 阅读(4391) 评论(8) 编辑

根据typeName获取Type较为完备的办法

前年还在开发.NET产品,我那时候编写一个C#脚本解释引擎,遇到一个问题是,Type.GetType()方法无法获取尚未装载类型。这些天,在阅读一些相关的代码时,得知了一种较为完整的方法,共享如下:

 
internal static Type FindTypeInCurrentDomain(string typeName)
 
{
      Type type 
= null;
  
      
//如果该类型已经装载
      type = Type.GetType(typeName);
      
if (type != null)
      
{
           
return type;
      }


      
//在EntryAssembly中查找
      if (Assembly.GetEntryAssembly() != null)
      
{
           type 
= Assembly.GetEntryAssembly().GetType(typeName);
           
if (type != null)
           
{
                
return type;
           }

      }


      
//在CurrentDomain的所有Assembly中查找
      Assembly[] assemblyArray = AppDomain.CurrentDomain.GetAssemblies();
      
int assemblyArrayLength = assemblyArray.Length;
      
for (int i = 0; i < assemblyArrayLength; ++i)
      
{
           type 
= assemblyArray[i].GetType(typeName);
           
if (type != null)
           
{
                
return type;
           }

      }


      
for (int i = 0; (i < assemblyArrayLength); ++i)
      
{
           Type[] typeArray 
= assemblyArray[i].GetTypes();
           
int typeArrayLength = typeArray.Length;
           
for (int j = 0; j < typeArrayLength; ++j)
           
{
                
if (typeArray[j].Name.Equals(typeName))
                
{
                     
return typeArray[j];
                }

           }

      }


      
return type;
 }

posted @ 2004-07-07 22:43 温少 阅读(882) 评论(2) 编辑

JDBC和ADO .NET

 我最先学习.NET,使用了大约三年后,就转向在Java上开发程序。刚开始使用JDBC时,觉得其接口比较奇怪,奇怪的地方如下:
 1、PreparedStatement派生自Statement,但是Statement中的一些public的方法,例如execute(String sql)等方法,使不能被PreparedStatement的实例调用的。
 2、其参数的计数是从1开始的,而不是我们习惯使用的0。这是一个地雷,等着你去踩的,最初使用的人,通常都会踩中地雷,我想JDBC的设计者此时就会偷笑,哈哈!又有一个SB中招了……
 3、PreparedStatement的setString()方法,不区分NChar和Char,这使得一些数据库的Driver无法支持NChar和NVarchar类型的数据。如Oracle 8i的JDBC Driver是明确写了不支持NChar、NVachar2类型。在Oracle 9i的Driver中有一种专有的实现setFormOfUse(...),可以解决此问题,但如此一来,就不可以基于JDBC接口编程了,也无法更换JDBC Driver了。

 JDBC接口的设计者一定是一个整蛊专家!!

 ADO.NET 带了一系列支持Disconnected访问数据的类,包括DataSet、DataTable等,使得访问数据很简单,其接口也很方便使用。ADO.NET具备微软产品使用简单的优点,也和微软产品的一贯作风一样,显得有点小家子气。其中一点就是,虽然SqlClient、OracleClient、OleDb、Odbc等DbProvider都是继承同样的接口,但是这并不能使你可以在ADO.NET中基于接口编程。其中一个原因是,其不同的DbProvider的Sql的参数风格是不一样的。SQL Server使用@ParameterName风格的命名参数,Oracle使用:ParameterName的风格,而OleDb和Odbc都使用匿名参数。天下大乱,一蹋糊涂!!!

 在ADO.NET中,更换DbProvider并不如JDBC那么容易,可以说ADO.NET的开放性比JDBC差。ADO .NET 2.0似乎在这方面做了一些增强的措施。但是还是不如JDBC!

posted @ 2004-07-07 22:42 温少 阅读(704) 评论(0) 编辑

大家是否有更好的方法?

对于Singleton模式的类,有一部分代码是相同的,是否能够通过泛型来实现?
 以下是现在想到的有缺陷的一个方式。以下方式的缺陷是,MySingletonClass必须
 拥有缺省的public的构造函数。大家是否有更好的方法?
(以下代码基于C# 2.0)
public class Singleton<T> where T : new()
 
{
 
private static T _instance;

 
public static T Instance
 
{
 
get
 
{
 
if (_instance == null)
 
{
 
lock (typeof(Singleton<T>))
 
{
 
if (_instance == null)
 
{
 _instance 
= new T();
 }

 }

 }


 
return _instance;
 }

 }

 }


 
public class MySingletonClass : Singleton<MySingletonClass>
 
{
 
public MySingletonClass () 
 
{
 }

 }

posted @ 2004-07-07 22:41 温少 阅读(641) 评论(3) 编辑

如何调用只有私有构造函数的类

当我试用ObjectSpaces时,ObjectSpaces竟然能够调用只有私有构造函数的类。例如:

Class A
{
private A() {}
}

ObjectSpaces能够创建A的实例,我刚看到的时候,吃了一惊,呵呵…… 后来,借助Reflector分析整理学会了此技巧。

你不能通过Reflection直接创建只有私有构造函数的类,但是你可以通过一些偏门技巧绕过此限制。

其大概思路这样的:

private CreateInstanceDelegate<T> BuildDelegate<T>()
{
Type type 
= typeof(T);

AssemblyName assemblyName 
= new AssemblyName();
assemblyName.Name 
= "System.Data.ObjectSpaces.Dynamic";

AssemblyBuilder assemblyBuilder 
= AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);

Module module 
= assemblyBuilder.DefineDynamicModule("WebData""DynamicAssembly.dll"true);

Type[] paramTypeArray 
= new Type[] {};
Type rtnType 
= type;
String methodName 
= "call_privateCtor";
bool skipVisibility = true;

DynamicMethod method 
= new DynamicMethod(
methodName,
rtnType, 
paramTypeArray, 
module,
skipVisibility
);

ConstructorInfo ctor 
= type.GetConstructor(
BindingFlags.NonPublic 
| BindingFlags.Public | BindingFlags.Instance,
null,
new Type[0],
null
);

ILGenerator ilGen 
= method.GetILGenerator();
ilGen.Emit(OpCodes.Newobj, ctor);
ilGen.Emit(OpCodes.Ret);

以上是思路,我们也来写一段代码,让其能够调用缺省构造函数创建对象实例,具体代码:

第一步, 定义一个Delegate:

public delegate T CreateInstanceDelegate<T>();

第二步,定义构建Delegate的方法,关键在此:

private CreateInstanceDelegate<T> BuildDelegate<T>()
{
Type type 
= typeof(T);

AssemblyName assemblyName 
= new AssemblyName();
assemblyName.Name 
= "System.Data.ObjectSpaces.Dynamic";

AssemblyBuilder assemblyBuilder 
= AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);

Module module 
= assemblyBuilder.DefineDynamicModule("WebData""DynamicAssembly.dll"true);

Type[] paramTypeArray 
= new Type[] {};
Type rtnType 
= type;
String methodName 
= "call_privateCtor";
bool skipVisibility = true;

DynamicMethod method 
= new DynamicMethod(
methodName,
rtnType, 
paramTypeArray, 
module,
skipVisibility
);

ConstructorInfo ctor 
= type.GetConstructor(
BindingFlags.NonPublic 
| BindingFlags.Public | BindingFlags.Instance,
null,
new Type[0],
null
);

ILGenerator ilGen 
= method.GetILGenerator();
ilGen.Emit(OpCodes.Newobj, ctor);
ilGen.Emit(OpCodes.Ret);

return (CreateInstanceDelegate<T>) method.CreateDelegate(typeof(CreateInstanceDelegate<T>));
}


第三步,定义创建实例的方法:

public T CreateInstance<T>()
{
CreateInstanceDelegate
<T> createInstDelegate = BuildDelegate<T>();
return createInstDelegate();
}

第四步,如此使用:
定义一个私有缺省构造函数的类

class A
{
private A() {}
}

创建实例的代码:

A a = CreateInstance<A>();
Console.WriteLine(
"create A instance");

posted @ 2004-07-07 22:38 温少 阅读(1726) 评论(6) 编辑

一个很好的Java查BUG工具

经一个朋友介绍,发现了一个很好的Java环境下的查错工具findBugs。
这个工具的真的很棒,使用这个工具发现了我代码中一些小BUG,人毕竟是人,就是会犯错误,工具比人强。令人吃惊的是,这个工具检查可能导致Connection、Statement、ResultSet这些资源类忘记关闭的BUG,这个功能特别强。例如:

Conneciton conn = ...;
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);

这样的代码,在异常发生的情况下可能导致资源泄露。findBugs能够检查异常发生情况下可能发生的BUG,真的很强。

这里有文章介绍:
http://www-900.ibm.com/developerWorks/cn/java/j-findbug1/index.shtml
http://www-900.ibm.com/developerWorks/cn/java/j-findbug1/index.shtml

下载:
http://findbugs.sourceforge.net/

建议:立刻使用findBugs检查你的代码。

感概,Java是一个开放的世界,开放的资源很多,也很棒,如junit、log4j、ant、hibernate、findBugs、open for business等等。拥抱Java,拥抱开放!!

posted @ 2004-07-07 22:31 温少 阅读(1027) 评论(3) 编辑

关于多数据库支持产品SwisSQL

发现一个支持多数据的产品,也是这样的思路:
Common SQL -->(翻译) Dialect SQL

该产品的网站:
http://www.swissql.com/

下载下来安装后,安装目录下,有一个SwisSQLAPI.jar,这个jar中,有一个类:
com.adventnet.swissqlapi.SwisSQLAPI,这类就是完成翻译的功能。

例如:

String sql = "select top 10 * from t order by f1";
SwisSQLAPI api = new SwisSQLAPI(sql);
String db2_result = api.convert(SwisSQLAPI.DB2);
System.out.println(db2_result);
String oracle_result = api.convert(SwisSQLAPI.ORACLE);
System.out.println(oracle_result);
String mysql_result = api.convert(SwisSQLAPI.MYSQL);
System.out.println(mysql_result);
 
输出:
SELECT * FROM  t  ORDER BY f1  FETCH FIRST 10 ROWS ONLY 
SELECT *  FROM (SELECT * FROM  t  ORDER BY f1) WHERE  ROWNUM  < 11
SELECT * FROM  t  ORDER BY f1  LIMIT 10 

评述:
SwisSQL支持的数据库挺多的,但是其稳定性应该一般,一些重要的SQL功能都有翻译错误的。例如:
SELECT * FROM  T1 LEFT JOIN T2 ON T1.ID  = T2.ID
在Sybase、MS SQL Server的翻译结果显然是错的。
猜想,SwisSQL应该尚未经过产品应用的测试,或者只经过很少应用的检验。

该公司的客户很多,但不一定是使用了该产品来实现多数据库支持,而是作为辅助迁移工具吧。

国内公司有相应的产品,很多方面作得比SwisSQL好!!

posted @ 2004-07-07 22:29 温少 阅读(1437) 评论(8) 编辑

不同数据库对树状数据递归查询支持

Oracle对树形数据的递归查询使用Connect子句,例如:
以下内容为程序代码:

SELECT ID, PARENTID, Level 
FROM TREENODE 
Start 
With ID = 'A2' 
Connect 
By Prior ID = ParentId

在DB2和最新的MS SQL Server 2005中也支持递归查询。SQL Server 2005和DB 2语法是相似的。

如上的SQL在DB 2中应为:

WITH SUB_TABLE (ID, PARENTID, Level
AS (
  
SELECT ID, PARENTID, 0 FROM TREENODE WHERE ID = 'A2' 
  
UNION ALL 
  
SELECT PRIOR_TAB.ID, PRIOR_TAB.PARENTID, KSQL_SUB_TABLE.Level + 1 
    
FROM (SELECT ID, PARENTID, Level FROM TREENODE) PRIOR_TAB, SUB_TABLE 
  
WHERE SUB_TABLE.ID = PRIOR_TAB.ParentId
)
SELECT ID, PARENTID, Level FROM SUB_TABLE

 

DB2中递归查询使用起来,比Oracle的麻烦。Oracle中引入了Prior关键字,使得递归查询变得简单。

MS SQL Server在最新2005的版本中,终于支持递归查询了,相比起Oracle和DB2,落后了好多年哟!!

posted @ 2004-07-07 22:26 温少 阅读(2125) 评论(2) 编辑