C#での「使用」の用途は何ですか?


319

ユーザーkokosは、キーワードに言及することで、C#のすばらしい隠し機能の質問に回答しましたusing。詳しく説明できますか?の用途はusing何ですか?


これは、RAIIイディオムをサポートするC#の方法です。hackcraft.net
Nemanja Trifunovic

1
IDisposeインターフェイスを実装したオブジェクトに使用できます。を使用すると、そのオブジェクトがスコープから外れたときにDisposeメソッドが呼び出されます。例外が発生した場合でも、Disposeの呼び出しを保証します。finally節のように機能し、Disposeを実行します。
CharithJ 2015

回答:


480

usingステートメントの理由は、オブジェクトがスコープから外れるとすぐにオブジェクトが確実に破棄されるようにするためであり、これが発生することを確認するために明示的なコードを必要としません。

同様にC#(CodeProjectの)に声明」を使用しての理解IDisposableを(Microsoft)を実装するオブジェクトを使用して、C#コンパイラ変換を

using (MyResource myRes = new MyResource())
{
    myRes.DoSomething();
}

{ // Limits scope of myRes
    MyResource myRes= new MyResource();
    try
    {
        myRes.DoSomething();
    }
    finally
    {
        // Check for a null resource.
        if (myRes != null)
            // Call the object's Dispose method.
            ((IDisposable)myRes).Dispose();
    }
}

C#8では、「using宣言」という名前の新しい構文が導入されています。

using宣言は、usingキーワードに続く変数宣言です。これは、宣言されている変数を囲んでいるスコープの最後に配置する必要があることをコンパイラーに通知します。

したがって、上記と同等のコードは次のようになります。

using var myRes = new MyResource();
myRes.DoSomething();

コントロールが包含スコープ(通常はメソッドですが、コードブロックにすることもできます)を離れると、破棄myResされます。


129
オブジェクトが正しく配置されるかどうかは問題ではありませんが、適切なタイミングで配置されるかどうかが重要です。ストリームやファイルハンドルなどのアンマネージリソースを保持するIDisposableを実装するオブジェクトは、ガベージコレクション中にDisposeが確実に呼び出されるファイナライザーも実装します。問題は、GCが比較的長時間発生しない可能性があることです。オブジェクトの処理が完了すると、using必ずDispose呼び出されます。
John Saunders

1
MyRessource構造体の場合、生成されるコードは少し異なることに注意してください。明らかに、無効性のテストはありませんが、へのボクシングもありませんIDisposable。制約された仮想呼び出しが発生します。
Romain Verdier 2014年

4
名前空間のインポートにも使用が使用されていることに誰も言及していないのはなぜですか?
カイルデラニー2017年

3
コードの2番目のバージョンを直接記述する場合、結果は同じではないことに注意してください。を使用する場合using、内部に構築された変数は読み取り専用です。usingステートメントなしでローカル変数に対してこれを達成する方法はありません。
Massimiliano Kraus

1
@JohnSaundersさらに、ファイナライザの呼び出しは保証されていません。
Pablo H

124

多くの人がまだやっているので:

using (System.IO.StreamReader r = new System.IO.StreamReader(""))
using (System.IO.StreamReader r2 = new System.IO.StreamReader("")) {
   //code
}

多くの人はあなたができることをまだ知らないと思います:

using (System.IO.StreamReader r = new System.IO.StreamReader(""), r2 = new System.IO.StreamReader("")) {
   //code
}

2
1つのusingステートメントで異なるタイプの複数のオブジェクトを使用することは可能ですか?
Agnel Kurian 2013

12
@AgnelKurianいいえ:「エラーCS1044:for、using、fixed、または宣言ステートメントでは複数のタイプを使用できません」
David Sykes

10
これはどのように質問に答えますか?
リアム

私は実際には、単一のコードブロックの前に、statemensを使用して2つを作成できることを知りませんでした(それらを毎回ネストします)。
kub1x 2018年

97

このようなもの:

using (var conn = new SqlConnection("connection string"))
{
   conn.Open();

    // Execute SQL statement here on the connection you created
}

これは、SqlConnection明示的に呼び出すために必要とせずに閉じられます.Close()機能を、これが起こるのだろう例外がスローされた場合でもを必要とせずに、try/ catch/ finally


1
メソッド内で「using」を使用していて、usingの途中で戻った場合はどうなりますか。何か問題ある?
francisco_ssb 2016年

1
問題ありません。この例でreturnは、usingブロックの真ん中からでも、接続は閉じられます。
Joel Coehoorn 16年

30

usingを使用してIDisposableを呼び出すことができます。タイプのエイリアスにも使用できます。

using (SqlConnection cnn = new SqlConnection()) { /*code*/}
using f1 = System.Windows.Forms.Form;

21

使用するという意味で

using (var foo = new Bar())
{
  Baz();
}

実際には、try / finallyブロックの省略形です。それはコードと同等です:

var foo = new Bar();
try
{
  Baz();
}
finally
{
  foo.Dispose();
}

もちろん、最初のスニペットは2番目のスニペットよりもはるかに簡潔であり、例外がスローされた場合でもクリーンアップとして実行する必要のある多くの種類の処理があることに注意してください。このため、Disposeメソッドで任意のコードを実行できるようにするScopeと呼ばれるクラスを用意しました。したがって、たとえば、操作を実行した後に常にfalseに設定したいIsWorkingというプロパティがある場合は、次のようにします。

using (new Scope(() => IsWorking = false))
{
  IsWorking = true;
  MundaneYetDangerousWork();
}

私たちのソリューションとその導出方法については、こちらをご覧ください


12

Microsoftのドキュメントには、を使用すると、ディレクティブとしてもステートメント内でも、二重の機能(https://msdn.microsoft.com/en-us/library/zhdeatwt.aspx)があると記載されています。ステートメントとして、他の回答でここで指摘されているように、キーワードは基本的に、IDisposableオブジェクトを破棄するスコープを決定する構文上の砂糖です。ディレクティブとして、名前空間と型をインポートするために日常的に使用されます。また、指令として、エイリアスを作成できます「C#5.0 In a Nutshell:The Definitive Guide」(http://www.amazon.com/5-0-Nutshell-The-)で指摘され名前空間と型のを。 Definitive-Reference-ebook / dp / B008E6I1K8)、ジョセフとベンアルバハリによる。一例:

namespace HelloWorld
{
    using AppFunc = Func<IDictionary<DateTime, string>, List<string>>;
    public class Startup
    {
        public static AppFunc OrderEvents() 
        {
            AppFunc appFunc = (IDictionary<DateTime, string> events) =>
            {
                if ((events != null) && (events.Count > 0))
                {
                    List<string> result = events.OrderBy(ev => ev.Key)
                        .Select(ev => ev.Value)
                        .ToList();
                    return result;
                }
                throw new ArgumentException("Event dictionary is null or empty.");
            };
            return appFunc;
        }
    }
}

この慣習の乱用は自分のコードの明瞭さを損なう可能性があるので、これは賢明に採用するものです。DotNetPearls(http://www.dotnetperls.com/using-alias)には、C#エイリアスに関する良い説明があり、賛否両論についても説明されています


4
嘘をつくつもりはありません。エイリアスツールとしての使用は嫌いusingです。コードを読むと混乱します- System.Collections存在し、IEnumerable<T>クラスがあることはすでに知っています。エイリアスを使用してそれを別の名前で呼び出すと、わかりにくくなります。私はusing FooCollection = IEnumerable<Foo>、後の開発者にコードを読んで「地獄とは何か、FooCollectionどこかにそのクラスがどこにないのか」と考える方法だと思います。私はそれを決して使用せず、その使用を思いとどまらせるでしょう。しかし、それは私だけかもしれません。
Ari Roth

1
補遺:デリゲートを定義するために使用する例のように、時々それが使用される可能性があることを認めます。しかし、私はそれらが比較的まれであることを主張します。
Ari Roth

10

これまで、入力ストリームと出力ストリームを操作するためによく使用しました。それらをうまく入れ子にすることができ、(自動的にdisposeを呼び出すことによって)よくある潜在的な問題の多くを取り除きます。例えば:

        using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
        {
            using (BufferedStream bs = new BufferedStream(fs))
            {
                using (System.IO.StreamReader sr = new StreamReader(bs))
                {
                    string output = sr.ReadToEnd();
                }
            }
        }

8

びっくりしたことをちょっと加えただけでは思いつかなかった。(私の意見では)を使用する最も興味深い機能は、usingブロックを終了する方法が重要ではなく、常にオブジェクトを破棄することです。これには、返品と例外が含まれます。

using (var db = new DbContext())
{
    if(db.State == State.Closed) throw new Exception("Database connection is closed.");
    return db.Something.ToList();
}

例外がスローされるか、リストが返されるかは関係ありません。DbContextオブジェクトは常に破棄されます。


6

を使用するもう1つの優れた用途は、モーダルダイアログをインスタンス化するときです。

Using frm as new Form1

Form1.ShowDialog

' do stuff here

End Using

1
もしかしてfrm.ShowDialog?
UuDdLrLrSs 2017

5

結論として、あなたは実装がその型のローカル変数を使用する場合IDisposable必ず、例外なく、使用using1

非ローカルIDisposable変数を使用する場合は、常にIDisposableパターンを実装してください。

2つの単純なルール、例外なし1。それ以外の方法でリソースリークを防止することは、* ssの大きな問題です。


1):唯一の例外は–例外を処理しているときです。その場合Disposefinallyブロックで明示的に呼び出すコードが少なくなる可能性があります。


5

次の例のように、エイリアス名前空間を利用できます。

using LegacyEntities = CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects;

ご覧のとおり、これは別名エイリアスディレクティブと呼ばれます。コードで参照しているものをコードで明確にしたい場合は、長い参照を非表示にするために使用できます。

LegacyEntities.Account

の代わりに

CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects.Account

または単に

Account   // It is not obvious this is a legacy entity

4

興味深いことに、他の興味深いもの(Rhino Mocksが使用する方法の他のポイントなど)にusing / IDisposableパターンを使用することもできます。基本的に、コンパイラーは常に「使用された」オブジェクトに対して.Disposeを呼び出すます。特定の操作の後に発生する必要がある何か(明確な開始と終了があるもの)がある場合は、コンストラクターで操作を開始し、Disposeメソッドで終了するIDisposableクラスを作成できます。

これにより、非常に使いやすい構文を使用して、上記の操作の明示的な開始と終了を示すことができます。これは、System.Transactionsの動作方法でもあります。


3

ADO.NETを使用する場合、接続オブジェクトやリーダーオブジェクトなどにキーワークを使用できます。これにより、コードブロックが完了すると、接続が自動的に破棄されます。


2
コードブロックが完了する必要さえないことを追加します。未使用の例外が発生した場合でも、usingブロックはリソースを破棄します。
harpo

さらに明確にするために、ガベージコレクターが割り当てを適切に処理するのではなく、必要なときに処理するようにする方法です。
moswald 2008


3
public class ClassA:IDisposable

{
   #region IDisposable Members        
    public void Dispose()
    {            
        GC.SuppressFinalize(this);
    }
    #endregion
}

public void fn_Data()

    {
     using (ClassA ObjectName = new ClassA())
            {
                //use objectName 
            }
    }

2

usingは、使用後に破棄したいリソースがある場合に使用されます。

たとえば、Fileリソースを割り当て、コードの1つのセクションでそれを使用する必要がある場合は、使用すると、すぐにFileリソースを破棄できます。

使用されているリソースが正しく機能するには、IDisposableを実装する必要があります。

例:

using (File file = new File (parameters))
{
    *code to do stuff with the file*
}

1

usingキーワードは、オブジェクトのスコープを定義し、スコープが完了したときにオブジェクトを破棄します。例えば。

using (Font font2 = new Font("Arial", 10.0f))
{
    // use font2
}

C#を使用したキーワードに関するMSDNの記事については、こちらをご覧ください。


1

それが非常に重要であるというわけではありませんが、使用はその場でリソースを変更するためにも使用できます。はい、前述のように使い捨てですが、おそらく残りの実行中にリソースが他のリソースと一致しないようにしたくない場合があります。したがって、他の場所に干渉しないように廃棄する必要があります。


1

以下のコメントのおかげで、私はこの投稿を少し整理します(当時、「ガベージコレクション」という言葉は使用すべきではありませんでした。お詫び申し上げます):
usingを使用すると、オブジェクトのDispose()メソッドが呼び出されます使用範囲の最後。したがって、Dispose()メソッドにかなりのクリーンアップコードを含めることができます。
おそらくこれがマークダウンされない可能性がある、ここでの箇条書きポイント:IDisposableを実装する場合は、Dispose()実装でGC.SuppressFinalize()を呼び出してください。少なくとも、Dispose()dを既に実行している場合は、少なくともリソースの無駄になります。


間接的な効果があります。オブジェクトを明示的に破棄したので、ファイナライズは不要であり、そのため以前にGCすることができます。
ケントブーガート2008

1

オブジェクトが直ちに破棄される合理的な使用の別の例:

using (IDataReader myReader = DataFunctions.ExecuteReader(CommandType.Text, sql.ToString(), dp.Parameters, myConnectionString)) 
{
    while (myReader.Read()) 
    {
        MyObject theObject = new MyObject();
        theObject.PublicProperty = myReader.GetString(0);
        myCollection.Add(theObject);
    }
}

1

中括弧の外側はすべて破棄されるため、使用しない場合はオブジェクトを破棄することをお勧めします。これは、SqlDataAdapterオブジェクトがあり、アプリケーションライフサイクルで1回だけ使用していて、1つのデータセットのみを入力していて、それが不要になった場合は、コードを使用できるためです。

using(SqlDataAdapter adapter_object = new SqlDataAdapter(sql_command_parameter))
{
   // do stuff
} // here adapter_object is disposed automatically

1

usingステートメントは、IDisposableオブジェクトを正しく使用するための便利なメカニズムを提供します。原則として、IDisposableオブジェクトを使用する場合は、usingステートメントで宣言してインスタンス化する必要があります。usingステートメントは、オブジェクトのDisposeメソッドを正しい方法で呼び出します。また、(前述のように使用すると)Disposeが呼び出されるとすぐに、オブジェクト自体がスコープ外になります。usingブロック内では、オブジェクトは読み取り専用であり、変更または再割り当てすることはできません。

これは以下から来ています:here


1

名前空間またはステートメント(ここで説明したものなど)をインポートしてエラー処理を行うためのディレクティブである可能性があるため、私にとって「using」という名前は少し混乱します。

エラー処理に別の名前を付けた方がいいでしょうし、おそらくもっと明白な名前になっているでしょう。


1

また、例のスコープの作成にも使用できます。

class LoggerScope:IDisposable {
   static ThreadLocal<LoggerScope> threadScope = 
        new ThreadLocal<LoggerScope>();
   private LoggerScope previous;

   public static LoggerScope Current=> threadScope.Value;

   public bool WithTime{get;}

   public LoggerScope(bool withTime){
       previous = threadScope.Value;
       threadScope.Value = this;
       WithTime=withTime;
   }

   public void Dispose(){
       threadScope.Value = previous;
   }
}


class Program {
   public static void Main(params string[] args){
       new Program().Run();
   }

   public void Run(){
      log("something happend!");
      using(new LoggerScope(false)){
          log("the quick brown fox jumps over the lazy dog!");
          using(new LoggerScope(true)){
              log("nested scope!");
          }
      }
   }

   void log(string message){
      if(LoggerScope.Current!=null){
          Console.WriteLine(message);
          if(LoggerScope.Current.WithTime){
             Console.WriteLine(DateTime.Now);
          }
      }
   }

}

1

usingステートメントは、usingブロックで指定されたオブジェクトが不要になったら解放するように.NETに指示します。したがって、System.IOタイプのように、後にクリーンアップが必要なクラスには「using」ブロックを使用する必要があります。


1

usingC#のキーワードには、次の2つの使用法があります。

  1. 指示として

    通常、usingキーワードを使用して、分離コードファイルとクラスファイルに名前空間を追加します。次に、現在のページのすべてのクラス、インターフェース、抽象クラス、およびそれらのメソッドとプロパティを利用できるようにします。

    例:

    using System.IO;
  2. ステートメントとして

    これはusing、C#でキーワードを使用する別の方法です。これは、ガベージコレクションのパフォーマンスを向上させる上で重要な役割を果たします。

    このusingステートメントにより、オブジェクトを作成してメソッドやプロパティなどを呼び出すときに例外が発生した場合でも、Dispose()が確実に呼び出されます。Dispose()は、カスタムガベージコレクションの実装に役立つIDisposableインターフェイスにあるメソッドです。言い換えると、データベース操作(挿入、更新、削除)を実行しているのに、どういうわけか例外が発生した場合、usingステートメントは接続を自動的に閉じます。接続のClose()メソッドを明示的に呼び出す必要はありません。

    もう1つの重要な要素は、接続プーリングに役立つことです。.NETの接続プールは、データベース接続を何度も閉じることをなくすのに役立ちます。接続オブジェクトを将来の使用のためにプールに送信します(次のデータベース呼び出し)。次にアプリケーションからデータベース接続が呼び出されたときに、接続プールはプールで使用可能なオブジェクトをフェッチします。したがって、アプリケーションのパフォーマンスを向上させるのに役立ちます。したがって、usingステートメントを使用すると、コントローラーがオブジェクトを接続プールに自動的に送信するので、Close()メソッドとDispose()メソッドを明示的に呼び出す必要はありません。

    tryステートメントとcatchブロックを使用して、usingステートメントと同じことを実行し、finallyブロック内でDispose()を明示的に呼び出すことができます。しかし、usingステートメントは呼び出しを自動的に実行して、コードをよりクリーンで洗練されたものにします。usingブロック内では、オブジェクトは読み取り専用であり、変更または再割り当てすることはできません。

    例:

    string connString = "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;";
    
    using (SqlConnection conn = new SqlConnection(connString))
    {
          SqlCommand cmd = conn.CreateCommand();
          cmd.CommandText = "SELECT CustomerId, CompanyName FROM Customers";
          conn.Open();
          using (SqlDataReader dr = cmd.ExecuteReader())
          {
             while (dr.Read())
             Console.WriteLine("{0}\t{1}", dr.GetString(0), dr.GetString(1));
          }
    }

上記のコードでは、接続を閉じていません。自動的に閉じます。usingステートメントは、のために自動的に)(はconn.closeを呼び出しますusing(ステートメントusing (SqlConnection conn = new SqlConnection(connString))とSqlDataReaderオブジェクトに同じ。また、例外が発生した場合は、接続を自動的に閉じます。

詳細については、「C#での使用と使用の重要性」を参照してください。



-1

ステートメントとして使用すると、指定したオブジェクトのdisposeが自動的に呼び出されます。オブジェクトはIDisposableインターフェイスを実装する必要があります。同じタイプのオブジェクトであれば、1つのステートメントで複数のオブジェクトを使用できます。

CLRはコードをMSILに変換します。そしてusingステートメントはtryに変換され、最終的にブロックされます。これは、ILでusingステートメントを表す方法です。usingステートメントは、取得、使用、および廃棄の3つの部分に変換されます。最初にリソースが取得され、次に使用法がfinally節を含むtryステートメントで囲まれます。オブジェクトは、finally句に配置されます。


-3

句の使用は、特定の変数のスコープを定義するために使用されます。例えば:

     Using(SqlConnection conn=new SqlConnection(ConnectionString)
            {
                Conn.Open()
            // Execute sql statements here.
           // You do not have to close the connection explicitly here as "USING" will close the connection once the object Conn becomes out of the defined scope.
            }

これは、オブジェクトを破棄するためにを使用して、誰かを誤解させる可能性があります。これをコードブロックと混同している可能性があります。変数のスコープを制限する場合は、ネストされたコードブロックを使用できます
。public
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.