发现C#的重大缺陷或Bug

lucky5168 2015-02-21 04:15:11
本人最近想把一个Java程序转换到C#,但碰到C#一个重大缺陷。为此专门做了一个简单的Win Form程序来证明这个缺陷。请看下面的代码。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace TestDb2
{
public class AccessDb
{
string connstr = "Provider=Microsoft.Jet.OLEDB.4.0 ;Data Source=C:\\tmp\\finance.mdb";
System.Data.OleDb.OleDbConnection conn = null;
public AccessDb()
{
conn = new System.Data.OleDb.OleDbConnection(connstr);
conn.Open();
}

~AccessDb()
{
conn.Close();
conn.Dispose();
}
}

public partial class Form1 : Form
{
AccessDb db = null;
public Form1()
{
InitializeComponent();
db = new AccessDb();
}
}
}

上面程序中有一个类AccessDb,该类的析构函数执行了关闭数据库连接操作。但运行时出错,当程序运行到析构函数时,系统报句柄conn未被初始化。

在类的析构函数中执行一些释放资源的操作是很普通的,该操作在C++,Java中都是可以的,但唯独在C#中碰到了问题。笔者认为这是C#的重大缺陷,因为系统显然在析构函数被调用之前就把这个类的成员变量的对象都销毁了。C++和Java可都不是这样的,这违反常理啊!

各位大神有什么看法和解决之道?本人就是想在类被销毁的时候访问成员变量做一些善后工作,看来在析构函数里不能做了,在哪里可以做?
...全文
2481 78 打赏 收藏 转发到动态 举报
写回复
用AI写文章
78 条回复
切换为时间正序
请发表友善的回复…
发表回复
小K的大师兄 2015-03-09
  • 打赏
  • 举报
回复
编程不要死脑筋
於黾 2015-03-09
  • 打赏
  • 举报
回复
引用 73 楼 Z65443344 的回复:
[quote=引用 72 楼 CANL464970302 的回复:] 自己拉的屎,Java和C中需要自己擦,但C#不需要,这个马桶比较溜,自带擦屎器
C#是自动冲水马桶,还带洗PP的功能,不用自己擦的[/quote] 明明使用了自动冲水,自动洗PP的马桶,还说:为什么我每次擦PP的时候,马桶都出一股水把纸弄湿了,这太BUG了
  • 打赏
  • 举报
回复
引用 40 楼 q3310017 的回复:
你想用c#,却遵行java的思想,然后说:c#错了。 错的不是你,是世界
对。 错的是世界。
Justin-Liu 2015-03-09
  • 打赏
  • 举报
回复
我是看标题进来的,看了看就不想看了,我走了 不评论,呵呵~
bigbaldy 2015-03-09
  • 打赏
  • 举报
回复
说一门语言有重大bug之前请先对这门语言有个了解,资源释放请严格按照微软官方给的例子:

class BaseClass : IDisposable
{
   // Flag: Has Dispose already been called?
   bool disposed = false;

   // Public implementation of Dispose pattern callable by consumers.
   public void Dispose()
   { 
      Dispose(true);
      GC.SuppressFinalize(this);           
   }

   // Protected implementation of Dispose pattern.
   protected virtual void Dispose(bool disposing)
   {
      if (disposed)
         return; 

      if (disposing) {
         // Free any other managed objects here.
         //
      }

      // Free any unmanaged objects here.
      //
      disposed = true;
   }

   ~BaseClass()
   {
      Dispose(false);
   }
}
以上例子中的每一个点都很重要,资源释放这块微软设计的很严谨的!为何要调用 GC.SuppressFinalize(this)?为何析构中的Dispose的参数是false?我想楼主看明白后就知道你错在哪了,也就明白这不是语言的bug,而是你代码写的不对,官方有清晰的文档告诉你应该怎么写,你偏不这么写,出了问题还赖人家?
於黾 2015-03-09
  • 打赏
  • 举报
回复
引用 72 楼 CANL464970302 的回复:
自己拉的屎,Java和C中需要自己擦,但C#不需要,这个马桶比较溜,自带擦屎器
C#是自动冲水马桶,还带洗PP的功能,不用自己擦的
CANL464970302 2015-03-09
  • 打赏
  • 举报
回复
自己拉的屎,Java和C中需要自己擦,但C#不需要,这个马桶比较溜,自带擦屎器
alex_suen 2015-03-07
  • 打赏
  • 举报
回复
哎呀,我听不得别人说发现xx语言的重大缺陷之类的问题了
ahdung 2015-03-06
  • 打赏
  • 举报
回复
我觉得,LZ的求真和敢于否定的精神是好样的。很多楼层都没有正面回答LZ的疑问,而是转而应该怎么怎么做的争论,但回到LZ的代码层面,我真不觉得有什么问题,你可以说它不应该这样来释放资源,有更科学合理的做法巴拉巴拉~但他就是这样了,clr有什么理由不允许? 30楼的说法是在析构之前可能conn已经被释放,这个猜测算是有道理,算是正面回答LZ的疑问,但经过我实践,也不是那么回事,conn在进入析构时仍然是一个state为open的连接,但执行到conn.Close就异常了,我的异常跟LZ描述的不一样,具体不贴了,赶时间先闪人,待机缘巧合弄清楚这个问题再交流。
marswangbo 2015-03-05
  • 打赏
  • 举报
回复
我觉得好歹得先判断下是否为NULL吧。。。。
於黾 2015-03-05
  • 打赏
  • 举报
回复
在用面向过程的思路来编程,还大谈C#不面向对象
FTD_Fred 2015-02-28
  • 打赏
  • 举报
回复
为什么我感觉这问题讨论着讨论着就偏题了……
layershow 2015-02-28
  • 打赏
  • 举报
回复
那么问题来了: 请用你认为不是 BUG 的方式实现类似 delete obj; 的调用 Dispose 是什么,你懂得,delete 是面向对象的风格吗?
  • 打赏
  • 举报
回复
引用 40 楼 q3310017 的回复:
你想用c#,却遵行java的思想,然后说:c#错了。 错的不是你,是世界
C#与Java的垃圾回收也不完全一样的,何况楼主还带着强烈的非托管编程思想,如楼上所说C#的析构函数跟C++中的不一样,CSDN上有明确的说明,建议的方案是使用IDispose接口来释放非托管资源,实际占用的内存由GC按照配置的策略与内存使用情况来择机释放
qzyf1992 2015-02-27
  • 打赏
  • 举报
回复
我想试问你放在析构函数里,如果这个对象存在的时间很长,其中有一个方法执行的是io操作 比如操作word,excel什么的 那这个数据库连接有必要打开么? 如果io操作有10分钟那么这个数据库连接就得打开10分钟?如果是高并发的网络环境要占据你服务器多少内存?LZ考虑过这个内存泄露的问题么? 随用随放固然增加了dispose的次数,但是由于ado.net内部做的连接池的优化无疑是一种非常好的处理方式。
qzyf1992 2015-02-27
  • 打赏
  • 举报
回复
我完全没搞懂为什么释放数据库连接你要放在析构函数里。 既然知道连接是非常宝贵的资源 那就应该做到随用随放,而且ado.net已经做过很多优化,随用随放根本不会消耗很多系统资源。这就lz所谓的 这就是c#的重要缺陷? 而且报这个错本身就是.net的机制在调用你的析构函数的时候就已经掉用过 connection的析构函数了 只不过没有显示调用dispose而已。 而调用析构函数之后确实就是无法显示调用其dispose方法。这更加强调的一点是在走对象的析构函数之前要对conn做dispose操作,我个人认为微软这样的处理是更好的。如果你非要把其他语言的那一套搬过来我也无话可说。每个语言都有自己的处理方式,除非你能说出c++的处理方式比c#好在哪里
yang1216 2015-02-27
  • 打赏
  • 举报
回复
又涨姿势啦。
qq_25621861 2015-02-27
  • 打赏
  • 举报
回复
学习了
john_QQ:2335298917 2015-02-27
  • 打赏
  • 举报
回复
看到各位大神的回复,感觉对C#的理解又深刻了许多
  • 打赏
  • 举报
回复
引用 39 楼 wyd1520 的回复:
他的意思是说: 30楼是正确的。使用Java或C#,当不确定一个对象是否存在时,首先要做的事情就是NULL判断。实际上,初级开发者出现的许多BUG都像lucky5168那样,在一个不再存在的对象上调用属性或方法的做法是应该避免的。
加载更多回复(56)

110,536

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧