「C Sharpその他 - 使用すべき機能」の版間の差分

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動
(Wiki がページ「C Sharpの基礎 - 使用すべき機能」を「C Sharpその他 - 使用すべき機能」に、リダイレクトを残さずに移動しました)
(文字列「source lang」を「syntaxhighlight lang」に置換)
20行目: 20行目:
*: EAPは、結果をイベントで返すものである。末尾がAsyncのメソッドとCompletedのイベントのペアを使用する。
*: EAPは、結果をイベントで返すものである。末尾がAsyncのメソッドとCompletedのイベントのペアを使用する。
*: 例えば、WebClientクラス(System.Net名前空間)が、EAP型の非同期APIを持っている。
*: 例えば、WebClientクラス(System.Net名前空間)が、EAP型の非同期APIを持っている。
  <source lang="c#">
  <syntaxhighlight lang="c#">
  var wc = new WebClient { Encoding = Encoding.UTF8 };
  var wc = new WebClient { Encoding = Encoding.UTF8 };
   
   
38行目: 38行目:
*: .NET Framework 4.5では、標準ライブラリ中の非同期APIにTAP版が用意されている。
*: .NET Framework 4.5では、標準ライブラリ中の非同期APIにTAP版が用意されている。
*: 例えば、WebRequestクラスのメソッドにも、TAP版が用意されます。
*: 例えば、WebRequestクラスのメソッドにも、TAP版が用意されます。
  <source lang="c#">
  <syntaxhighlight lang="c#">
  var req = WebRequest.Create("http://ufcpp.net/study/csharp/");
  var req = WebRequest.Create("http://ufcpp.net/study/csharp/");
  req.GetResponseAsync().ContinueWith(t =>
  req.GetResponseAsync().ContinueWith(t =>
56行目: 56行目:
*: C# 5.0では、さらに、非同期処理を、同期版と同じ構造のままで記述できるasync / awaitという機能が追加された。
*: C# 5.0では、さらに、非同期処理を、同期版と同じ構造のままで記述できるasync / awaitという機能が追加された。
*: 上記の例を、async /awaitを使用して記述し直すと、以下のようになる。
*: 上記の例を、async /awaitを使用して記述し直すと、以下のようになる。
  <source lang="c#">
  <syntaxhighlight lang="c#">
  private static async Task SampleAsync()
  private static async Task SampleAsync()
  {
  {
79行目: 79行目:
*: イテレータ構文もLINQも無い場合は、以下のように記述していた。
*: イテレータ構文もLINQも無い場合は、以下のように記述していた。
*: この記述方法では、一時的にListを生成しているので、データ量が増加すると、多くのメモリを消費する。
*: この記述方法では、一時的にListを生成しているので、データ量が増加すると、多くのメモリを消費する。
  <source lang="c#">
  <syntaxhighlight lang="c#">
  using System;
  using System;
  using System.Collections.Generic;
  using System.Collections.Generic;
132行目: 132行目:
* 現在の記述方法
* 現在の記述方法
*: イテレータ構文とLINQを使用して、一時的なListクラスを生成しない。
*: イテレータ構文とLINQを使用して、一時的なListクラスを生成しない。
  <source lang="c#">
  <syntaxhighlight lang="c#">
  using System;
  using System;
  using System.Collections.Generic;
  using System.Collections.Generic;
176行目: 176行目:
<span style="color:#C00000">'''ポイント : メソッドの引数や戻り値、プロパティの型には、IEnumerable<T> を使う。'''</span><br>
<span style="color:#C00000">'''ポイント : メソッドの引数や戻り値、プロパティの型には、IEnumerable<T> を使う。'''</span><br>
データ列に対して、前から順に1要素ずつ読む操作のみを行う場合、List<T>クラスや配列ではなく、IEnumerable<T>インターフェイスを使う。<br>
データ列に対して、前から順に1要素ずつ読む操作のみを行う場合、List<T>クラスや配列ではなく、IEnumerable<T>インターフェイスを使う。<br>
  <source lang="c#">
  <syntaxhighlight lang="c#">
  // ダメなコード
  // ダメなコード
  // この記述では、配列の内容を書き換えられる
  // この記述では、配列の内容を書き換えられる
191行目: 191行目:
  </source>
  </source>
<br>
<br>
  <source lang="c#">
  <syntaxhighlight lang="c#">
  // 良いコード
  // 良いコード
  // 読み取り専用なら、IEnumerableにする
  // 読み取り専用なら、IEnumerableにする
217行目: 217行目:
*: .NET 3.5から、XDocumentクラスが追加された。IEnumerable<XElement>で要素一覧を読み出せるので、LINQ to Objectsが使える。
*: .NET 3.5から、XDocumentクラスが追加された。IEnumerable<XElement>で要素一覧を読み出せるので、LINQ to Objectsが使える。
<br>
<br>
  <source lang="c#">
  <syntaxhighlight lang="c#">
  var doc = XDocument.Load(filename);
  var doc = XDocument.Load(filename);
  var ns = doc.Root.Name.Namespace;
  var ns = doc.Root.Name.Namespace;
234行目: 234行目:
後からの変更に備えて、ただフィールドを読み書きするだけのプロパティを作ることがある。<br>
後からの変更に備えて、ただフィールドを読み書きするだけのプロパティを作ることがある。<br>
下記のようにすれば、後から処理を加えることになっても、 クラスの利用側の再コンパイルは不要である。<br>
下記のようにすれば、後から処理を加えることになっても、 クラスの利用側の再コンパイルは不要である。<br>
  <source lang="c#">
  <syntaxhighlight lang="c#">
  private int _x;
  private int _x;
   
   
247行目: 247行目:
<br>
<br>
また、外部からは読み取り専用なプロパティを作る場合は、以下のように記述する。<br>
また、外部からは読み取り専用なプロパティを作る場合は、以下のように記述する。<br>
  <source lang="c#">
  <syntaxhighlight lang="c#">
  public int X
  public int X
  {
  {

2021年11月17日 (水) 07:55時点における版

概要

新しい構文やライブラリが導入されたことで、記述方法が変わったものがある。
ここでは、その記述方法をまとめる。


使用すべき機能

マルチスレッド

ポイント : Taskクラスを使う。
時間がかかる処理は、マルチスレッドにすべきである。
特に、ネットワーク処理等、待ち時間の長い処理にはマルチスレッドが必須である。

  • 以前(C# 1.0 / 1.1)の記述方法
    C# 1.0 / 1.1では、APM(Asynchronous Programming Model)というものがある。
    APMは、IAsyncResultを返すまたは受け取るBegin / Endメソッドのペアを使用する。
    例えば、WebRequestクラス(System.Net名前空間)は、APM型の非同期APIを持っている。
    ここでは、サンプルコードは割愛する。


  • 以前(C# 2.0)の記述方法
    C# 2.0では、EAP(Event-based Asynchronous Pattern)という記述方法が流行った。
    EAPは、結果をイベントで返すものである。末尾がAsyncのメソッドとCompletedのイベントのペアを使用する。
    例えば、WebClientクラス(System.Net名前空間)が、EAP型の非同期APIを持っている。
<syntaxhighlight lang="c#">
var wc = new WebClient { Encoding = Encoding.UTF8 };

wc.DownloadStringCompleted += (sender, args) =>
{
   var result = args.Result;
   Console.WriteLine(result);
};

wc.DownloadStringAsync(new Uri("http://ufcpp.net/study/csharp/"));
</source>


  • C# 4.0の記述方法
    APMやEAPでは、複数の非同期処理を繋いで、1つの非同期APIにする作業が面倒だった。
    .NET Framework 4.0で導入されたTaskクラスでは、複数の非同期処理を繋ぐことが簡潔に記述できるようになった。
    そこで、非同期APIも、Taskクラスを返すメソッドを1つだけ用意するTAP(Task-based Asynchronous Pattern)という記述方法が今後の主流になる。
    .NET Framework 4.5では、標準ライブラリ中の非同期APIにTAP版が用意されている。
    例えば、WebRequestクラスのメソッドにも、TAP版が用意されます。
<syntaxhighlight lang="c#">
var req = WebRequest.Create("http://ufcpp.net/study/csharp/");
req.GetResponseAsync().ContinueWith(t =>
                                   {
                                      var res = t.Result;

                                      string result = null;
                                      using (var reader = new StreamReader(res.GetResponseStream()))
                                      {
                                         result = reader.ReadToEnd();
                                      }
                                      Console.WriteLine(result);
                                   });
</source>


  • C# 5.0の記述方法
    C# 5.0では、さらに、非同期処理を、同期版と同じ構造のままで記述できるasync / awaitという機能が追加された。
    上記の例を、async /awaitを使用して記述し直すと、以下のようになる。
<syntaxhighlight lang="c#">
private static async Task SampleAsync()
{
   using(var req = WebRequest.Create(@"http://ufcpp.net/study/csharp/"))
   {
      var res = await req.GetResponseAsync();

      string result = null;
      using (var reader = new StreamReader(res.GetResponseStream()))
      {
         result = reader.ReadToEnd();
      }
      Console.WriteLine(result);
   }
}
</source>


LINQ

ポイント: LINQ を使えば、不要な一時リストを使わない。
データを入力、加工後、集計して表示したいサンプルコードを以下に示す。

  • 以前の記述方法
    イテレータ構文もLINQも無い場合は、以下のように記述していた。
    この記述方法では、一時的にListを生成しているので、データ量が増加すると、多くのメモリを消費する。
<syntaxhighlight lang="c#">
using System;
using System.Collections.Generic;

class Program
{
   static void Main()
   {
      var inputs = ReadIntFromConsole();
      var mapped = Square(inputs);

      foreach (var y in mapped)
      {
         Console.WriteLine("入力の二乗: {0}", y);
      }
   }

   static IEnumerable<int> ReadIntFromConsole()
   {
      var list = new List<int>();
      while (true)
      {
         var line = Console.ReadLine();

         if (string.IsNullOrWhiteSpace(line))
         {
            break;
         }

         int x;
         if (!int.TryParse(line, out x))
         {
               break;
         }
         list.Add(x);
      }
      return list;
   }

   static IEnumerable<int> Square(IEnumerable<int> source)
   {
      var list = new List<int>();
      foreach (var x in source)
      {
         list.Add(x * x);
      }
      return list;
   }
}
</source>


  • 現在の記述方法
    イテレータ構文とLINQを使用して、一時的なListクラスを生成しない。
<syntaxhighlight lang="c#">
using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
   static void Main()
   {
      var inputs = ReadIntFromConsole();
      var mapped = inputs.Select(x => x * x);

      foreach (var y in mapped)
      {
         Console.WriteLine("入力の二乗: {0}", y);
      }
   }

   static IEnumerable<int> ReadIntFromConsole()
   {
      while (true)
      {
         var line = Console.ReadLine();

         if (string.IsNullOrWhiteSpace(line))
         {
            break;
         }

         int x;
         if (!int.TryParse(line, out x))
         {
            break;
         }
         yield return x; // イテレータ構文
       }
   }
}
</source>


IEnumerableを使う

ポイント : メソッドの引数や戻り値、プロパティの型には、IEnumerable<T> を使う。
データ列に対して、前から順に1要素ずつ読む操作のみを行う場合、List<T>クラスや配列ではなく、IEnumerable<T>インターフェイスを使う。

<syntaxhighlight lang="c#">
// ダメなコード
// この記述では、配列の内容を書き換えられる
static readonly int[] SampleData = { 1, 2, 3, 4, 5 };

// 読み取り専用にも関わらず、int[]で受け取っている
static void Output(int[] data)
{
   foreach (var x in data)
   {
      Console.WriteLine(x);
   }
}
</source>


<syntaxhighlight lang="c#">
// 良いコード
// 読み取り専用なら、IEnumerableにする
static readonly IEnumerable<int> SampleData = { 1, 2, 3, 4, 5, };

// 上記と同様に、引数の型もIEnumerableにする
static void Output(IEnumerable<int> data)
{
   foreach (var x in data)
   {
      Console.WriteLine(x);
   }
}
</source>


XML

ポイント : XDocumentクラス(System.Xml.Linq名前空間)を使う。
C# 3.0/.NET 3.5にて、LINQが導入されたことで、データ処理においてIEnumerable<T>インターフェイスが特別な意味を持つようになった。
それに合わせて、XMLの読み書きのためにも、IEnumerableでXML要素一覧を読み出せるようなクラスが新たに追加された。

  • 以前の記述方法
    .NET 3.0以前では、XmlDocumentクラス(System.Xml名前空間)を使っていた。


  • 現在の記述方法
    .NET 3.5から、XDocumentクラスが追加された。IEnumerable<XElement>で要素一覧を読み出せるので、LINQ to Objectsが使える。


<syntaxhighlight lang="c#">
var doc = XDocument.Load(filename);
var ns = doc.Root.Name.Namespace;

var titles = from x in doc.Root.Elements(ns + "section")
             select x.Attribute("title").Value;

foreach (var title in titles)
{
   Console.WriteLine(title);
}
</source>


自動実装プロパティ

ポイント : フィールドをpublicにしてはいけない。自動実装プロパティを使用する
後からの変更に備えて、ただフィールドを読み書きするだけのプロパティを作ることがある。
下記のようにすれば、後から処理を加えることになっても、 クラスの利用側の再コンパイルは不要である。

<syntaxhighlight lang="c#">
private int _x;

public int X
{
   get;
   set;
   //get { return _x; }
   //set { _x = value; }
}
</source>


また、外部からは読み取り専用なプロパティを作る場合は、以下のように記述する。

<syntaxhighlight lang="c#">
public int X
{
   get;
   private set;
}
</source>