20201014のC#に関する記事は8件です。

C# で Azure Functions の CORS にドメインを登録

Azure SDK for .NET を使用して C# で Azure Functions の CORS にドメインを登録する方法をまとめます。

image.png

事前準備

CORS の登録処理の認証に使用する AAD のアプリを用意し、クライアント ID、クライアントシークレット、テナント ID を取得しておきます。

AAD のアプリは CORS 登録対象の Azure Functions か、Azure Functions のリソースグループにロールを割り当てておきます。
今回はリソースグループに「共同作成者」でロールを割り当てました。

次に、CORS の登録対象の Azure Functions のサブスクリプション ID を取得しておきます。

AAD アプリの情報、サブスクリプション ID を変数に設定しておきます。

var clientId = "{AAD アプリのクライアント ID}";
var clientSecret = "{AAD アプリのクライアントシークレット}";
var tenantId = "{AAD アプリのテナント ID}";
var subscriptionId = "{CORS の登録対象の Azure Functions のサブスクリプション ID}";

資格情報の作成

Nuget より Microsoft.Azure.Management.ResourceManager.Fluent をインストールします。

AAD のアプリの clientId, clientSecret, tenantId を使用して資格情報を作成します。

// credential の作成
var credentials = SdkContext.AzureCredentialsFactory
    .FromServicePrincipal(clientId, clientSecret, tenantId, AzureEnvironment.AzureGlobalCloud);

Azure SDK for .NET のリファレンスはこちら

Azure オブジェクトの作成

Nuget より Microsoft.Azure.Management.Fluent をインストールします。

資格情報で作成した AzureCredentials オブジェクトと、サブスクリプション ID を使用して CORS を操作するための Azure オブジェクトを作成します。

// Azure オブジェクトの作成
var azure = Microsoft.Azure.Management.Fluent.Azure
            .Configure()
            .Authenticate(credentials)
            .WithSubscription(subscriptionId);

Azure SDK for .NET のリファレンス

CORS 一覧取得

リソースグループ名、FunctionApp 名を元に更新対象の FunctionApp の CORS の一覧を取得します。

CORS 一覧は IList<string> 型で取得されます。

var functionAppName = "{CORS 登録対象の Azure Functions}";
var resourceGroupName = "{CORS 登録対象の Azure Functions のリソースグループ名}";

// WebApps の config を取得
var siteConfig = (await azure.WebApps.Inner.GetConfigurationWithHttpMessagesAsync(resourceGroupName, functionAppName)).Body;
// config から CORS の一覧を取得
var corsList = siteConfig.Cors.AllowedOrigins;

Azure SDK for .NET のリファレンスはこちら

CORS の登録

CORS の一覧に登録するドメインを追加し、WebApps の config を更新することで FunctionApp の CORS にドメインを登録することができます。

// COSR の一覧に登録するドメインを追加
var additionalDomain = "{登録するドメイン}";
corsList.Add(additionalDomain);

// CORS の一覧を設定
var newSiteConfig = new SiteConfigResourceInner() { Cors = new CorsSettings() };
newSiteConfig.Cors.AllowedOrigins = corsList;

// WebApps の config を更新
await azure.WebApps.Inner.CreateOrUpdateConfigurationWithHttpMessagesAsync(resourceGroupName, functionAppName, newSiteConfig);

Azure SDK for .NET のリファレンスはこちら

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ReactiveProperty 7.5.0-pre202010141113 をリリースしました

ReactiveProperty v7.5.0 のプレリリース版を NuGet に公開しました。

ReactiveProperty 7.5.0-pre202010141113

変更内容は以下のような感じです。

ObservePropertyToReactivePropertyAsSynchronizedToReactivePropertySlimAsSynchronizedx.Hoge.Foo みたいにプロパティがネストしているケースもサポートしました。

例えば、以下のようなコードを書くと Person クラスの Child プロパティの Name プロパティを監視する ReadOnlyReactivePropertySlim が出来ます。

var p = new Person();
var rp = p.ObserveProperty(x => x.Child.Name)
  .ToReadOnlyReactivePropertySlim();

今までは、上記のようなコードを書いても動いていませんでした。途中で Child を null に設定すると Name プロパティの型の default 値が ReactiveProperty に設定されます。
一度 Child に null を設定しても、再度 null じゃない値が設定されると、その時の Child の Name の監視が行われて ReactiveProperty に設定されます。

ToReactivePropertyAsSyncronizedToReactivePropertySlimAsSyncronized は、プロパティの途中の値が null などになると、null の間に ReactiveProperty の Value に設定された値は無視されます。

ぼちぼちコードを追加したので、とりあえず pre 版としてリリースしてみました。まだ GitHub の PullRequest で絶賛作業中です。

https://github.com/runceel/ReactiveProperty/pull/199

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Visual Studio 2019 で一括フォーマットしたい

Visual Studio 2019 で全ファイル一括フォーマットしたい!

こんな拡張機能があります。

https://marketplace.visualstudio.com/items?itemName=munyabe.FormatAllFiles

image.png

個人的には、この拡張機能は使ってなくてちょっとした C# のコードの一括フォーマットだと dotnet format コマンドを使ったりしてます。

https://github.com/dotnet/format

image.png

インストールは以下のコマンドを叩けば完了です。

dotnet tool install -g dotnet-format

毎回コマンドを叩くのもだるいので、Visual Studio 2019 の外部ツールに以下のように登録しておくと開いているソリューションのファイルを全部フォーマットしてくれるようになります。

image.png

ごくごくまれにやりたくなる。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

EF Core のマイグレーションがすごい便利だった

Windows アプリの DB 周りを調べていて、EF Core のマイグレーションがかなり便利だなと思ったので、構築手順とマイグレーション方法について記載します。

EF Core とは

公式サイトより引用です。

Entity Framework Core は、.NET 用の最新のオブジェクト データベース マッパーです。 LINQ クエリ、変更の追跡、更新、スキーマの移行がサポートされています。 EF Core は、SQL Database (オンプレミスと Azure)、SQLite、MySQL、PostgreSQL、Azure Cosmos DB などの多くのデータベースに対応しています。

環境

  • Visual Studio 2019
  • .NET Core 3.0
  • EF Core 3.1.7
  • SQLite

手順

1. WPF アプリのプロジェクトを新規作成し、以下の NuGet パッケージをインストールする

Install-Package Microsoft.EntityFrameworkCore.Sqlite
Install-Package Microsoft.EntityFrameworkCore.Proxies
Install-Package Microsoft.EntityFrameworkCore.Tools
  • Microsoft.EntityFrameworkCore.SQLite(SQLite 本体)
  • Microsoft.EntityFrameworkCore.Proxies(データの遅延読み込みサポート用)
  • Microsoft.EntityFrameworkCore.Tools(マイグレーション用)

2. EF Core のチュートリアルに記載のソース(C#、XAML)を一通り書き切る(ビルドはまだしない)

私が使ったのは EF Core のチュートリアルです。
WPF の使用を開始する - EF Core | Microsoft Docs

以下にサンプルコードもあるので、手書きせずともそちらを使っても大丈夫です。
GetStartedWPF

ただし、まだビルドはしないように気をつけてください。
理由は後ほど説明します。

3. MainWindow.xaml.csWindow_Loadedを以下の通り書き換える

MainWindow.xaml.cs
private void Window_Loaded(object sender, RoutedEventArgs e)
{
    // DBのマイグレーション
    _context.Database.Migrate();

    // load the entities into EF Core
    _context.Categories.Load();

    // bind to the source
    categoryViewSource.Source =
        _context.Categories.Local.ToObservableCollection();
}

具体的には、_context.Database.EnsureCreated();と書かれていたところを、_context.Database.Migrate();に書き換えます。
書き換える理由としては以下の通りです(公式ドキュメント引用)

データベースが既に存在する場合、EnsureCreated() によってデータベースのスキーマとシードデータが更新されないことに注意してください。 リレーショナルデータベースの場合、移行を使用する予定がある場合は EnsureCreated() を呼び出さないでください。

ビルドをしないでください、と言ったのもこのためです。
もしビルドをしてしまった場合は、生成されたproducts.dbを削除してください。

4. パッケージマネージャーコンソールで以下のコマンドを実行し、Migrations フォルダおよびその配下に C#ファイルがいくつか自動生成されることを確認する

Add-Migration InitialCreate
Update-Database

5. ビルド&アプリを実行する

products.dbが生成されるはずです。

マイグレーションのやり方

個人的に便利だと思ったのがこのマイグレーションです。
本来ならクエリ文を手書きして適用する形でいろいろめんどくさいのですが、EF Core ではクエリ文を手書きせずとも簡単なコマンドで簡単に実現できます。

1. Product.csに適当なカラムを追加するなどする

例えばProduct.csを以下のように書き換えてみます。

Product.cs
namespace GetStartedWPF
{
    public class Product
    {
        public int ProductId { get; set; }
        public string Name { get; set; }
        public int Price { get; set; } // 新しく追加したカラム
        public int CategoryId { get; set; }
        public virtual Category Category { get; set; }
    }
}

2. 以下のコマンドを実行し、Migrations フォルダの配下に C#ファイルが新たに自動生成されることを確認する

Add-Migration AddProductPrice
Update-Database

3. ビルド&アプリ実行

products.dbを見ると、1 で変更した内容が反映されているはずです。

UWP アプリで EF Core を使う際の注意

UWP アプリにて EF Core のマイグレーションをやるときは、App.xaml.csでマイグレーションしないと動かないので注意です。
WPF アプリなどを Windows アプリケーション パッケージ プロジェクトでパッケージングする場合も同様です。

App.xaml.cs
public App()
{
    using (var dbContext = new ProductContext())
        dbContext.Database.Migrate();
}

参考 URL

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

IAM認証のAWS API GatewayにC#からIAMユーザでSigV4署名してアクセスするには

IAM認証を使っているAWSのAPI Gatewayは、APIリクエスト時にSigV4署名が必要です。

S3にSigV4署名でアクセスする方法は、AWS公式の以下のページにJavaとC#でのサンプルがあります。

これをベースにIAM認証を使っているAPI GatewayにC#でアクセスしてみます。

Pythonならば、以前の記事(IAM認証のAWS API GatewayにPythonからSigV4署名してアクセスするには)で似たことをしました。

前提

IAMユーザのアクセスキーが ~/.aws/credentials に設定されていて、そのIAMユーザでAPI Gatewayにアクセスするものとします。API GatewayのリソースポリシーにはそのIAMユーザからのAPIアクセスを許可してあるものとします。

動作確認した環境はUbuntu 20.04です。

C#の環境は以下の通り。

$ dotnet --version
3.1.402

以下は私の記事でして、このとおりC#をほとんど始めて触っています。C#の流儀と違うところがあったらごめんなさい。

サンプルコードダウンロード

AWS公式のS3アクセスのサンプルをダウンロードします。

$ mkdir sample
$ cd sample
$ mkdir tmp
$ cd tmp
$ wget https://docs.aws.amazon.com/AmazonS3/latest/API/samples/AmazonS3SigV4_Samples_CSharp.zip
$ unzip AmazonS3SigV4_Samples_CSharp.zip
$ cd ..

$ tree
.
└── tmp
    ├── AmazonS3SigV4_Samples_CSharp.zip
    ├── AWSSignatureV4-S3-Sample
    │   ├── App.config
    │   ├── AWSSignatureV4-S3-Sample.csproj
    │   ├── GetS3ObjectSample.cs
    │   ├── POSTExampleForm.html
    │   ├── PostS3ObjectSample.cs
    │   ├── PresignedUrlSample.cs
    │   ├── Program.cs
    │   ├── Properties
    │   │   └── AssemblyInfo.cs
    │   ├── PutS3ObjectChunkedSample.cs
    │   ├── PutS3ObjectSample.cs
    │   ├── Signers
    │   │   ├── AWS4SignerBase.cs
    │   │   ├── AWS4SignerForAuthorizationHeader.cs
    │   │   ├── AWS4SignerForChunkedUpload.cs
    │   │   ├── AWS4SignerForPOST.cs
    │   │   └── AWS4SignerForQueryParameterAuth.cs
    │   └── Util
    │       └── HttpHelpers.cs
    └── AWSSignatureV4-S3-Sample.sln

5 directories, 18 files

IAMユーザを使ってS3アクセスするサンプルです。今回はこのうち、SignersUtil というディレクトリだけ使います。

$ mv tmp/AWSSignatureV4-S3-Sample/Signers ./
$ mv tmp/AWSSignatureV4-S3-Sample/Util ./
$ rm -r tmp

このサンプルはnamespaceが AWSSignatureV4_S3_Sample となっています。今回はS3ではないので、適当な名前 Sample に全置換します。(このコマンドの説明は sedコマンドでディレクトリ内の全ファイルをテキスト全置換するには)

$ grep -rl AWSSignatureV4_S3_Sample Signers | xargs sed -i 's/AWSSignatureV4_S3_Sample/Sample/g'
$ grep -rl AWSSignatureV4_S3_Sample Util | xargs sed -i 's/AWSSignatureV4_S3_Sample/Sample/g'

ここまでで以下のようなディレクトリ構成になります。

$ tree
.
├── Signers
│   ├── AWS4SignerBase.cs
│   ├── AWS4SignerForAuthorizationHeader.cs
│   ├── AWS4SignerForChunkedUpload.cs
│   ├── AWS4SignerForPOST.cs
│   └── AWS4SignerForQueryParameterAuth.cs
└── Util
    └── HttpHelpers.cs

2 directories, 6 files

C#のプロジェクト作成

dotnetコマンドでプロジェクトを作成します。

$ dotnet new console

以下のようなディレクトリ構成になります。

$ tree
.
├── obj
│   ├── project.assets.json
│   ├── project.nuget.cache
│   ├── sample.csproj.nuget.dgspec.json
│   ├── sample.csproj.nuget.g.props
│   └── sample.csproj.nuget.g.targets
├── Program.cs
├── sample.csproj
├── Signers
│   ├── AWS4SignerBase.cs
│   ├── AWS4SignerForAuthorizationHeader.cs
│   ├── AWS4SignerForChunkedUpload.cs
│   ├── AWS4SignerForPOST.cs
│   └── AWS4SignerForQueryParameterAuth.cs
└── Util
    └── HttpHelpers.cs

3 directories, 13 files

sample.csprojに以下のように RootNamespace の項目を追加します。サンプルダウンロード後に全置換したnamespaceを指定します。

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <RootNamespace>Sample</RootNamespace>
  </PropertyGroup>

</Project>

必要なパッケージをダウンロードします。 AWSSDK.Core だけで大丈夫です。今回はHTTP(S)でAPIアクセスするだけですので、API Gatewayのパッケージは不要です。

$ dotnet add package AWSSDK.Core

C#のソースコード

Program.cs は以下です。

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

using Amazon.Runtime.CredentialManagement;

using Sample.Signers;
using Sample.Util;

namespace Sample
{
    class Program
    {
        private static void Run()
        {
            // ~/.aws/credentials からアクセスキー、シークレットキーを読み取る
            var sharedFile = new SharedCredentialsFile();
            sharedFile.TryGetProfile("default", out CredentialProfile credentialProfile);

            var uri = new Uri("https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello");

            // 署名するためのソースとなるヘッダ情報
            var headers = new Dictionary<string, string>
            {
                {AWS4SignerBase.X_Amz_Content_SHA256, AWS4SignerBase.EMPTY_BODY_SHA256},
                {"content-type", "text/plain"}
            };

            // 署名を作成
            var signer = new AWS4SignerForAuthorizationHeader
            {
                EndpointUri = uri,
                HttpMethod = "GET",
                Service = "execute-api",
                Region = "ap-northeast-1"
            };
            var authorization = signer.ComputeSignature(headers,
                                                        "",   // no query parameters
                                                        AWS4SignerBase.EMPTY_BODY_SHA256,
                                                        credentialProfile.Options.AccessKey,
                                                        credentialProfile.Options.SecretKey);

            // リクエストヘッダに署名を追加
            headers.Add("Authorization", authorization);

            // リクエスト実行
            // HttpHelpers はUtilで定義
            HttpHelpers.InvokeHttpRequest(uri, "GET", headers, null);
        }

        static void Main(string[] args)
        {
            Run();
        }
    }
}

uriはAPI GatewayのAPIのURLを入れます。

実行

以下のコマンドで実行できます。

$ dotnet run

ダウンロードしたサンプルコードのSignersUtilにデバッグ用出力があるので、いろいろ表示されますが、最後にAPI Gatewayからのレスポンスが表示されます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityの条件分岐色々※随時更新

ゲームオブジェクトがアクティブかどうか

GameObject.activeSelf を使う。
activeSelf は、ゲームオブジェクトのアクティブ状態を読み取る専用のメソッド。
参考: GameObject-activeSelf - Unity スクリプトリファレンス

if(A.activeSelf == true)
{
  Debug.Log("Aがアクティブな場合表示される");
}

アクティブ状態に関するメソッドに、SetActive が存在するが、こちらはアクティブ状態の切り替えに使用されるため、アクティブ状態を利用した条件分岐には使えない。

// NG例
if(A.SetActive == true)
{
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C#の変数宣言と型・キャスト

C#の基本的な知識からおさらいしていきます。

全くプログラミングしたことない人でも分かる内容にすることができるかどうか自分なりの読解力の確認も兼ねて

エントリポイント

"dotnet new console -o HelloWorld"によって新たにプロジェクトを作成した場合、
Program.csファイルに下記のようなプログラムが書かれています。

Program.cs
using System;

namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

コンパイラ言語であるC#には"エントリポイント"という、「プログラムが開始するスタート地点」が存在します。
※1. インタプリタ言語は基本的にファイルの先頭から開始します
※2. コンパイラ言語とインタプリタ言語の違いについてはここでは深く触れません。参考URLだけ貼っておきます。
* インタプリタ言語とコンパイラ言語 (Qiita)
* コンパイラとインタプリタの違いは? (じゃぱざむ)

C#のエントリポイントは下記の通りMainと書かれている部分になるので、その中に書かれているコードがプログラム実行時に処理されていきます

Program.cs
static void Main(string[] args)
{
    // 何らかの処理
}

標準出力

今、この中に記述されている「Console.WriteLine("Hello World!")」とは、コンソールに"Hello World!"と表示するという命令文になります。
ここでは、コンソールへの表示のことを"標準出力"と呼びます。
※詳しくは下記サイトなどを参照ください

1.PNG

文字列以外にも数値や論理値を表示することも可能です。

Program.cs
Console.WriteLine("Hello World!");
Console.WriteLine(5);
Console.WriteLine(9.8);
Console.WriteLine(false);
出力
> Hello World!
> 5
> 9.8
> False

変数と型

さて、コンソールに表示する内容をただただ直書きしていくのはツラいので変数を使っていきましょう

Program.cs
string a = "Hello World!";
int b = 5;
double c = 9.8;
bool d = false;
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
Console.WriteLine(d);
出力
> Hello World!
> 5
> 9.8
> False

さて、出力は全く同じですがa~dの変数に値を入れて、変数を使用してコンソールへの表示を行っています。
変数を定義する部分を "宣言" と呼び、変数へ値を入れることを "代入" と呼びます。

変数宣言時に出てきたstring, int, double, boolなどがそれぞれの変数の "型" といい、変数を使う場合には必ず"型"とセットにしなければいけません。

C#の型は「値型」と「参照型」に分かれており、次表に示す型を "値型" と呼び、型名と表現できる値の範囲は表の通りです。
宣言した型の表現可能な範囲を超えた値を入れようとするとエラーが起きてしまいます。

型名 備考
bool true / false 2値
char 文字 16bit Unicode文字
sbyte -128 ~ 127 符号つき8bit整数
byte 0 ~ 255 符号なし8bit整数
short -32,768 ~ 32,767 符号つき16bit整数
ushort 0 ~ 65,535 符号なし16bit整数
int -2,147,483,648 ~ 2,147,483,647 符号つき32bit整数
uint 0 ~ 4,294,967,295 符号なし32bit整数
long -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 符号つき64bit整数
ulong 0 ~ 18,446,744,073,709,551,615 符号なし64bit整数
decimal -79,228,162,514,264,337,593,543,950,335 ~ 79,228,162,514,264,337,593,543,950,335 有効桁数28桁以上の10進数実数
float -3.4028235E+38 ~ 3.4028235E+38 単精度浮動小数点数
double -1.7976931348623157E+308 ~ 1.7976931348623157E+308 倍精度浮動小数点数

値型だけでも数が多いですが、実際のところそこまで厳密に値の範囲を制限したい場面は少ないので、
整数表現にはintを、実数表現にはdoubleを使うということを覚えられれば十分です。

上記、値型以外の型を "参照型" と呼び、多種多様な型が存在しますが、"string"=文字列型も参照型の一種となります。
また、参照型は自分で新たに作り出すことも可能です。

さて、ただ単に直書きを変数にしただけではまだ特にメリットが分からないので計算もさせてみます。

Program.cs
int a = 14;
int b = 5;
Console.WriteLine(a + b); //  和 :14 + 5
Console.WriteLine(a - b); //  差 :14 - 5
Console.WriteLine(a * b); //  積 :14 * 5
Console.WriteLine(a / b); //  商 :14 / 5
Console.WriteLine(a % b); // 剰余:14 % 5
出力
> 19
> 9
> 70
> 2
> 4

おかしなことに気づいたでしょうか?「14 / 5 = 2」になってしまっています。
これはC#に限らずですが、プログラミングでは基本的に整数型による計算の結果は整数型になるという決まりがある為です。

理論的には14 / 5 = 2.8になりますが、これを"整数"で表現するために小数部分を切り捨てし、2となります。(四捨五入ではなく切り捨てです)
試しに実数型であるdouble型で同じ計算をしてみると

Program.cs
double a = 14;
double b = 5;
Console.WriteLine(a / b); //  商 :14 / 5
出力
> 2.8

となることが確認できると思います。

キャスト(型変換)

別々の値型でも、ある一定の条件を満たせば型を変換することができます。これを "キャスト" と呼びます。

Program.cs
double a = 5;
int b = (int)a;
double c = b;
Console.WriteLine(a/2);
Console.WriteLine(b/2);
Console.WriteLine(c/2);
出力
> 2.5
> 2
> 2.5

(int)を付けることでdouble型である a をint型に変換して b とすることができました。これを "明示的キャスト" と呼びます。
一方で int型である b をそのままdouble型である c に代入しています。これを "暗黙的キャスト" と呼びます。

最初に"一定の条件を満たせば"と言いましたが、その条件とは下記のとおりです。

  • キャスト前よりもキャスト後の値の範囲が広い場合には暗黙的キャストが可能
  • キャスト前よりもキャスト後の値の範囲が狭い場合には明示的キャストが必要

※暗黙的キャスト可能な場合に明示的にキャストを書いても問題ありません。

上記の例では、「intの範囲32bit」<「doubleの範囲64bit」なのでint→doubleへは暗黙的キャストが可能ですが、その逆では明示的キャストが必要になります。
型の範囲が狭まるということは、元々の変数では表現できていた情報を失ってしまったり、変換時に許容範囲外の値を入れようとしてエラーが起きてしまったりする可能性があります。

Program.cs
double a = 9.81828;   // 
int b = (int)a;       // 9 (0.81828の損失)
double c = 5000000000;// 50億
int d = (int)c        // エラー(オーバーフロー)

また、明示的キャストが必要な場合にキャストを付けなかった場合には、コンパイルエラーが発生して警告されます。

Program.cs
double a = 5;
int b = a;
// コンパイルエラー
//   型 'double' を 'int' に暗黙的に変換できません。
//   明示的な変換が存在します (cast が不足していないかどうかを確認してください))

まずは変数宣言と型、キャストについてここまで。

次は関数とスコープ、グローバル変数とかですかねー

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C#_変数宣言と型・キャスト

C#の基本的な知識からおさらいしていきます。

全くプログラミングしたことない人でも分かる内容にすることができるかどうか自分なりの読解力の確認も兼ねて

本文は以下の記事の内容を前提に記述しています。

エントリポイント

"dotnet new console -o HelloWorld"によって新たにプロジェクトを作成した場合、
Program.csファイルに下記のようなプログラムが書かれています。

Program.cs
using System;

namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

コンパイラ言語であるC#には"エントリポイント"という、「プログラムが開始するスタート地点」が存在します。
※1. インタプリタ言語は基本的にファイルの先頭から開始します
※2. コンパイラ言語とインタプリタ言語の違いについてはここでは深く触れません。参考URLだけ貼っておきます。

C#のエントリポイントは下記の通りMainと書かれている部分になるので、その中に書かれているコードがプログラム実行時に処理されていきます

Program.cs
static void Main(string[] args)
{
    // 何らかの処理
}

標準出力

今、この中に記述されている「Console.WriteLine("Hello World!")」とは、コンソールに"Hello World!"と表示するという命令文になります。
ここでは、コンソールへの表示のことを"標準出力"と呼びます。
※詳しくは下記サイトなどを参照ください

1.PNG

文字列以外にも数値や論理値を表示することも可能です。

Program.cs
Console.WriteLine("Hello World!");
Console.WriteLine(5);
Console.WriteLine(9.8);
Console.WriteLine(false);
出力
> Hello World!
> 5
> 9.8
> False

変数と型

さて、コンソールに表示する内容をただただ直書きしていくのはツラいので変数を使っていきましょう

Program.cs
string a = "Hello World!";
int b = 5;
double c = 9.8;
bool d = false;
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
Console.WriteLine(d);
出力
> Hello World!
> 5
> 9.8
> False

さて、出力は全く同じですがa~dの変数に値を入れて、変数を使用してコンソールへの表示を行っています。
変数を定義する部分を "宣言" と呼び、変数へ値を入れることを "代入" と呼びます。

変数宣言時に出てきたstring, int, double, boolなどがそれぞれの変数の "型" といい、変数を使う場合には必ず"型"とセットにしなければいけません。

C#の型は「値型」と「参照型」に分かれており、次表に示す型を "値型" と呼び、型名と表現できる値の範囲は表の通りです。
宣言した型の表現可能な範囲を超えた値を入れようとするとエラーが起きてしまいます。

型名 備考
bool true / false 2値
char 文字 16bit Unicode文字
sbyte -128 ~ 127 符号つき8bit整数
byte 0 ~ 255 符号なし8bit整数
short -32,768 ~ 32,767 符号つき16bit整数
ushort 0 ~ 65,535 符号なし16bit整数
int -2,147,483,648 ~ 2,147,483,647 符号つき32bit整数
uint 0 ~ 4,294,967,295 符号なし32bit整数
long -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 符号つき64bit整数
ulong 0 ~ 18,446,744,073,709,551,615 符号なし64bit整数
decimal -79,228,162,514,264,337,593,543,950,335 ~ 79,228,162,514,264,337,593,543,950,335 有効桁数28桁以上の10進数実数
float -3.4028235E+38 ~ 3.4028235E+38 単精度浮動小数点数
double -1.7976931348623157E+308 ~ 1.7976931348623157E+308 倍精度浮動小数点数

値型だけでも数が多いですが、実際のところそこまで厳密に値の範囲を制限したい場面は少ないので、
整数表現にはintを、実数表現にはdoubleを使うということを覚えられれば十分です。

上記、値型以外の型を "参照型" と呼び、多種多様な型が存在しますが、"string"=文字列型も参照型の一種となります。
また、参照型は自分で新たに作り出すことも可能です。

さて、ただ単に直書きを変数にしただけではまだ特にメリットが分からないので計算もさせてみます。

Program.cs
int a = 14;
int b = 5;
Console.WriteLine(a + b); //  和 :14 + 5
Console.WriteLine(a - b); //  差 :14 - 5
Console.WriteLine(a * b); //  積 :14 * 5
Console.WriteLine(a / b); //  商 :14 / 5
Console.WriteLine(a % b); // 剰余:14 % 5
出力
> 19
> 9
> 70
> 2
> 4

おかしなことに気づいたでしょうか?「14 / 5 = 2」になってしまっています。
これはC#に限らずですが、プログラミングでは基本的に整数型による計算の結果は整数型になるという決まりがある為です。

理論的には14 / 5 = 2.8になりますが、これを"整数"で表現するために小数部分を切り捨てし、2となります。(四捨五入ではなく切り捨てです)
試しに実数型であるdouble型で同じ計算をしてみると

Program.cs
double a = 14;
double b = 5;
Console.WriteLine(a / b); //  商 :14 / 5
出力
> 2.8

となることが確認できると思います。

キャスト(型変換)

別々の値型でも、ある一定の条件を満たせば型を変換することができます。これを "キャスト" と呼びます。

Program.cs
double a = 5;
int b = (int)a;
double c = b;
Console.WriteLine(a/2);
Console.WriteLine(b/2);
Console.WriteLine(c/2);
出力
> 2.5
> 2
> 2.5

(int)を付けることでdouble型である a をint型に変換して b とすることができました。これを "明示的キャスト" と呼びます。
一方で int型である b をそのままdouble型である c に代入しています。これを "暗黙的キャスト" と呼びます。

最初に"一定の条件を満たせば"と言いましたが、その条件とは下記のとおりです。

  • キャスト前よりもキャスト後の値の範囲が広い場合には暗黙的キャストが可能
  • キャスト前よりもキャスト後の値の範囲が狭い場合には明示的キャストが必要

※暗黙的キャスト可能な場合に明示的にキャストを書いても問題ありません。

上記の例では、「intの範囲32bit」<「doubleの範囲64bit」なのでint→doubleへは暗黙的キャストが可能ですが、その逆では明示的キャストが必要になります。
型の範囲が狭まるということは、元々の変数では表現できていた情報を失ってしまったり、変換時に許容範囲外の値を入れようとしてエラーが起きてしまったりする可能性があります。

Program.cs
double a = 9.81828;   // 
int b = (int)a;       // 9 (0.81828の損失)
double c = 5000000000;// 50億
int d = (int)c        // エラー(オーバーフロー)

また、明示的キャストが必要な場合にキャストを付けなかった場合には、コンパイルエラーが発生して警告されます。

Program.cs
double a = 5;
int b = a;
// コンパイルエラー
//   型 'double' を 'int' に暗黙的に変換できません。
//   明示的な変換が存在します (cast が不足していないかどうかを確認してください))

まずは変数宣言と型、キャストについてここまで。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む