我一直在研究如何最好地用C#编写"正确"的网络代码.
我已经看过使用C#的"using"语句的一些例子,我认为这是一个很好的方法,但是我已经看到它与各种表达式的不一致使用.
例如,假设我有一些这样的代码:
TcpClient tcpClient = new TcpClient("url.com", 80);
NetworkStream tcpStream = tcpClient.GetStream();
StreamReader tcpReader = new StreamReader(tcpStream);
StreamWriter tcpWriter = new StreamWriter(tcpStream);
Run Code Online (Sandbox Code Playgroud)
显然,这段代码非常不稳定.所以,我已经看到一些代码将使用放在tcpClient上,这似乎很好.但是,NetworkStream是否还有需要清理的资源?那么StreamReader/Writer呢?
我是否需要在嵌套的using语句中包装所有4个语句?
如果是这样,当处理时间时会发生什么?StreamWriter不会关闭流并因此关闭套接字吗?然后当StreamReader,然后是NetworkStream,然后TcpClient各自经过他们的处理时会发生什么?
这提出了另一个问题.StreamReader和StreamWriter都由同一个流组成,谁拥有它?难道他们都不认为他们拥有它,因此都会试图摧毁它吗?或者框架是否知道流已经被破坏并且只是默默地忽略它?
看起来似乎只对链中的最后一个语句使用using语句,但是如果在GetStream()中抛出异常会发生什么?我不认为它会正确清理套接字,所以似乎多余的使用是必要的,以确保不会发生这种情况.
有没有人知道有关.net网络编程的最新书籍,最好是包含异常处理和资源管理章节的c#?或者也许网上有好文章?我能找到的所有书籍都来自.NET 1.1时代(Microsoft .NET Framework的网络编程,.NET中的网络编程等),所以这看起来像是一个需要一些好资源的话题.
编辑:
请不要让Marc的评论很好地阻止其他人评论这个:)
我想听听任何人对资源管理的建议或意见,特别是有关异步使用的建议或意见.
我对c#有点新手,更习惯脚本语言.我喜欢'使用'的想法,你实例化一个对象,然后只要你需要它就在它的范围内运行,然后当它完成它的目的时你让它自己处理掉.
但是,这对我来说并不自然.当人们向我展示使用它的例子时,我认为它是一个很好的工具,但在我自己的编程中解决它的问题从来没有发生过.
如何识别好的地方using以及如何将它与try-catch块结合使用.它们是否进入块内,或者您是否通常想在try块中包含using语句?
我想使用这行代码:
using (ADataContext _dc = new ADataContext(ConnectionString), BDataContext _dc2 = new BrDataContext(ConnectionString)){ // ...}
Run Code Online (Sandbox Code Playgroud)
这给出了编译错误:
不能在for,using,fixed或declartion语句中使用多个类型.
我觉得这可能吗?MSDN说它是:http://msdn.microsoft.com/en-us/library/yh598w02%28VS.80%29.aspx 在MSDN示例代码中使用了Font,它是类,因此也是引用类型以及我的两个DataContext类.
这里出了什么问题?我的尝试与MSDN示例有何不同?
我想知道你对我所涉及的编码风格问题的看法.我意识到可能没有明确的答案,但我想看看在一个方向或另一个方向是否有强烈的偏好.
我正在通过一个解决方案using在很多地方添加语句.我常常会遇到这样的事情:
{
log = new log();
log.SomeProperty = something; // several of these
log.Connection = new OracleConnection("...");
log.InsertData(); // this is where log.Connection will be used
... // do other stuff with log, but connection won't be used again
}
Run Code Online (Sandbox Code Playgroud)
其中log.Connection是OracleConnection,它实现了IDisposable.
在我的neatnik想要改变它:
{
using (OracleConnection connection = new OracleConnection("..."))
{
log = new log();
log.SomeProperty = something;
log.Connection = conn;
log.InsertData();
...
}
}
Run Code Online (Sandbox Code Playgroud)
但是,简洁的爱好者和稍微快速完成工作的人希望这样做:
{
log = new log();
log.SomeProperty = something;
using (log.Connection = new …Run Code Online (Sandbox Code Playgroud) 正如本文所述,关于在IDisposable对象上使用的用法,它说了一个有趣的词:
...使用块,在块结束后的某个时间自动调用Dispose方法.(它可能不是立即的;它取决于CLR.)
有趣的是" 它可能不是立即的;它取决于CLR ".任何人都可以提供更多细节吗?因为我们有一些奇怪的情况下,似乎在代码中使用(新MyDisposable()){...},块结束}后它不立即呼吁MyDisposable例如Dispose方法,但一段时间后.
更新:结论对我来说,在我看来,我在其他地方有问题.我认为可以在使用块结束后的某个时间调用Dispose方法.但是当它不是那样的时候,我必须在我的代码中的其他地方找到问题.谢谢你的回复!
如果使用using子句来处置连接,那么实现IDisposable的子句中的其他项是否也会自动处理?如果没有,您如何处理确保所有IDisposable项目自动处理?
public static DataTable ReturnDataTable(
string ConnectionString, string CommandTextString, CommandType CommandType,
int CommandTimeout, List<System.Data.SqlClient.SqlParameter> ParameterList = null)
{
using (System.Data.SqlClient.SqlConnection Connection =
new System.Data.SqlClient.SqlConnection())
{
Connection.ConnectionString = ConnectionString;
System.Data.SqlClient.SqlCommand Command =
new System.Data.SqlClient.SqlCommand();
Command.Connection = Connection;
Command.CommandText = CommandTextString;
Command.CommandType = CommandType;
Command.CommandTimeout = CommandTimeout;
if (ParameterList != null)
{
if (ParameterList.Count > 0)
{
foreach (SqlParameter parameter in ParameterList)
{
Command.Parameters.AddWithValue(
parameter.ParameterName, parameter.Value);
}
}
}
System.Data.DataTable DataTable = new System.Data.DataTable();
System.Data.SqlClient.SqlDataAdapter DataAdapter =
new System.Data.SqlClient.SqlDataAdapter();
DataAdapter.SelectCommand = Command; …Run Code Online (Sandbox Code Playgroud) 我已经开始使用实现IDisposable的类来使用using语句在流中编写块.这有助于保持正确的嵌套并避免丢失或错误放置的开始/结束部件.
基本上,构造函数编写块的开头(例如打开XML标记),Dispose()结束(例如关闭XML标记).示例是下面的UsableXmlElement(它适用于大型XML,因此内存中的LINQ to XML或XmlDocument不是选项).
但是,这些IDisposable不实现Microsoft推荐的复杂模式,使用Destructor/Finalizer,单独的Dispose(bool)方法和GC.SuppressFinalize().Dispose只是简单地写出end元素,就是这样.
这有什么不妥的,或者这是保持元素正确嵌套的好方法吗?
class UsableXmlElement : IDisposable
{
private XmlWriter _xwriter;
public UsableXmlElement(string name, XmlWriter xmlWriter)
{
_xwriter = xmlWriter;
_xwriter.WriteStartElement(name);
}
public void WriteAttribute<T>(string name, T value)
{
_xwriter.WriteStartAttribute(name);
_xwriter.WriteValue(value);
_xwriter.WriteEndAttribute();
}
public void WriteValue<T>(T value)
{
_xwriter.WriteValue(value);
}
public void Dispose()
{
_xwriter.WriteEndElement();
}
}
Run Code Online (Sandbox Code Playgroud)
用法是这样的:
var xWriter = new XmlWriter(...)
using(var rootElement = new UsableXmlElement("RootElement", xWriter)
{
rootElement.WriteAttribute("DocVersion", 123)
using(var innerElement = new UsableXmlElement("InnerElement", xwriter)
{
// write anything inside Inner element
}
} …Run Code Online (Sandbox Code Playgroud) 我有一个应用程序,我必须从DB获取大量数据.由于它未能获得所有这些行(它接近2,000,000行...),我在中断时将其剪切,并且每次执行sql查询时每次只获得200,000行.
我使用DataTable输入所有数据(意思是 - 所有2,000,000行应该在那里).
前几次运行很好.然后它以OutOfMemoryException失败.
我的代码如下:
private static void RunQueryAndAddToDT(string sql, string lastRowID, SqlConnection conn, DataTable dt, int prevRowCount)
{
if (string.IsNullOrEmpty(sql))
{
sql = generateSqlQuery(lastRowID);
}
if (conn.State == ConnectionState.Closed)
{
conn.Open();
}
using (IDbCommand cmd2 = conn.CreateCommand())
{
cmd2.CommandType = CommandType.Text;
cmd2.CommandText = sql;
cmd2.CommandTimeout = 0;
using (IDataReader reader = cmd2.ExecuteReader())
{
while (reader.Read())
{
DataRow row = dt.NewRow();
row["RowID"] = reader["RowID"].ToString();
row["MyCol"] = reader["MyCol"].ToString();
... //In one of these rows it returns the exception.
dt.Rows.Add(row);
} …Run Code Online (Sandbox Code Playgroud) 我面临一个普遍的问题,我无法找到一个很好的例子来尝试为自己.谷歌不是一个帮助.
想象一下这样的结构:
MailMessage mail = new MailMessage(sender, receiver);
using(SmtpClient client = new SmtpClient())
{
client.Host ...
client.Port ...
mail.subject ...
mail.body ...
client.SendAsync(mail);
}
Run Code Online (Sandbox Code Playgroud)
如果服务器很慢并且需要一段时间来接受邮件,该怎么办?是否有可能SmtpClient在操作完成之前进行处理?它会以任何方式被卷入或破坏吗?
对此有一般性的答案吗?这里的服务器速度太快,不知道怎么做试用.
如果考虑取消BackgroundWorker它总是完成当前的操作.在这里可能是相同的,或者可能不是......
假设我已经定义了一个类MyDisposable : IDisposable.我知道我可以IDisposable在using声明中提供一个硬编码的对象列表:
using (MyDisposable firstDisposable = new MyDisposable(),
secondDisposable = new MyDisposable())
{
// do something
}
Run Code Online (Sandbox Code Playgroud)
现在让我们说我有一些方法可以对我的一次性对象集合执行操作,我想在一个using语句中执行此操作.它可能看起来像这样(但是这当然不起作用,因为using块需要一个或多个IDisposable对象,而且我传递一个集合对象):
using (var myDisposables = GetMyDisposables())
{
foreach (var myDisposable in myDisposables)
{
DoSomething(myDisposable);
DoSomethingElse(myDisposable);
}
}
Run Code Online (Sandbox Code Playgroud)
为清楚起见,其他方法如下:
static List<MyDisposable> GetMyDisposables()
{
throw new NotImplementedException(); // return a list of MyDisposable objects
}
static void DoSomething(MyDisposable withMyDisposable)
{
// something
}
static void DoSomethingElse(MyDisposable withMyDisposable)
{
// something else
}
Run Code Online (Sandbox Code Playgroud)
有什么方法可以用using …
c# ×10
using-statement ×10
idisposable ×4
.net ×2
dispose ×2
asynchronous ×1
coding-style ×1
datareader ×1
exception ×1
sql ×1
stream ×1
xml ×1