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

Blazor WebAssembly 初期プロジェクト構成の入門

はじめに この記事は初期のプロジェクト構成内で説明可能な内容をまとめています。 ソリューションの構成 Qiita.Client: クライアント側の処理 Qiita.Server: サーバー側の処理 ログインやアカウント登録などはこっち Qiita.Shared: 両サイドで使われる処理 共通関数や、Model定義など クライアント側 ・Pages/Index.razor @page "/" <h1>Hello, world!</h1> Welcome to your new app. <SurveyPrompt Title="How is Blazor working for you?" /> @page "/"はアクセスURL <h1>Hello, world!</h1>やWelcome to your new app.はHTML分をそのまま使える。 <SurveyPrompt Title="How is Blazor working for you?" />はSurveyPromptという名前のコンポーネントを設置し、Titleという変数にHow is Blazor working for you?を代入している。 ・Shared/SurveyPrompt.razor <div class="alert alert-secondary mt-4" role="alert"> <span class="oi oi-pencil mr-2" aria-hidden="true"></span> <strong>@Title</strong> <span class="text-nowrap"> Please take our <a target="_blank" class="font-weight-bold" href="https://go.microsoft.com/fwlink/?linkid=2137916">brief survey</a> </span> and tell us what you think. </div> @code { // Demonstrates how a parent component can supply parameters [Parameter] public string Title { get; set; } } <div> ~ </div>は通常のHTMLやBootstrapを使っている。 @code { ~ }内にはC#コードを記述する。※HTMLの中でC#コードを使うには@Titleのように@を使用する。 [Parameter]は変数につける事で、呼ばれ元で設定が出来るようにする印。 ・Counter.razor @page "/counter" <h1>Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() { currentCount++; } } <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>は、@onclick="IncrementCount"の所で、クリックしたときにIncrementCount関数が実行されるように指定されている。 @currentCountはC#の変数が使われているが、IncrementCount関数が実行されるとインクリメントされ即時にGUIに反映される事をデバックすると確認出来る。 ・FetchData.razor @page "/fetchdata" @using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Components.WebAssembly.Authentication @using Qiita.Shared @attribute [Authorize] @inject HttpClient Http <h1>Weather forecast</h1> <p>This component demonstrates fetching data from the server.</p> @if (forecasts == null) { <p><em>Loading...</em></p> } else { <table class="table"> <thead> <tr> <th>Date</th> <th>Temp. (C)</th> <th>Temp. (F)</th> <th>Summary</th> </tr> </thead> <tbody> @foreach (var forecast in forecasts) { <tr> <td>@forecast.Date.ToShortDateString()</td> <td>@forecast.TemperatureC</td> <td>@forecast.TemperatureF</td> <td>@forecast.Summary</td> </tr> } </tbody> </table> } @code { private WeatherForecast[] forecasts; protected override async Task OnInitializedAsync() { try { forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast"); } catch (AccessTokenNotAvailableException exception) { exception.Redirect(); } } } @usingとする事で通常のC#の名前空間を設定出来る。 @attribute [Authorize]とする事でこのページにはログインして認証済のアカウントしかアクセスが出来なくなる。 @inject HttpClient Httpは、HttpClientが依存注入される。※依存注入が不明な方は、Newされたインスタンスがセットされるようなイメージでまずは問題なし。 @if (forecasts == null)のようにif分は@if{ ~ }と書く。 この例ではforecastsがnullとそうではないときで表示内容を切り替えている。 デバックすると分かるが切り替えは瞬時。 @foreach (var forecast in forecasts)のようにforeach文は`@foreach (var forecast in forecasts){ ~ }と書く。 protected override async Task OnInitializedAsync()は、ページを開いた際のロードイベント。 await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");でWeatherForecastControllerのGetメソッドを呼び出し、WeatherForecast[]で結果を受け取っている。 ・MainLayout.razor @inherits LayoutComponentBase <div class="page"> <div class="sidebar"> <NavMenu /> </div> <div class="main"> <div class="top-row px-4 auth"> <LoginDisplay /> <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a> </div> <div class="content px-4"> @Body </div> </div> </div> @inherits ~で継承している。 サイドバーにはNavMenuコンポーネント、ヘッダーにはLoginDisplayコンポーネントを表示させている。 @Bodyには各ページの内容が入る。 ・Program.cs 今後機能を追加していく中で設定を追加していくことになる。 サーバー側 ・WeatherForecastController.cs using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Qiita.Shared; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Qiita.Server.Controllers { [Authorize] [ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; private readonly ILogger<WeatherForecastController> _logger; public WeatherForecastController(ILogger<WeatherForecastController> logger) { _logger = logger; } [HttpGet] public IEnumerable<WeatherForecast> Get() { var rng = new Random(); return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)] }) .ToArray(); } } } [Authorize]をつける事で認証済のアカウントしかこのWebApiを使えないようになる。 public WeatherForecastController(ILogger<WeatherForecastController> logger)は、コンストラクタでILoggerを依存注入している。 [HttpGet]で、この関数はGetリクエストを受ける関数であると定義している。 ・Areasフォルダ ログインやアカウント作成ページなどの認証系のページが入るフォルダ。 デフォルトでは全て英語で表示されるため翻訳が必要になると思われるが、このフォルダにソースを入れ翻訳していくこととなる。 ・Data/ApplicationDbContext.cs using IdentityServer4.EntityFramework.Options; using Microsoft.AspNetCore.ApiAuthorization.IdentityServer; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; using Qiita.Server.Models; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Qiita.Server.Data { public class ApplicationDbContext : ApiAuthorizationDbContext<ApplicationUser> { public ApplicationDbContext( DbContextOptions options, IOptions<OperationalStoreOptions> operationalStoreOptions) : base(options, operationalStoreOptions) { } } } コードファーストでDBを更新していく場合などに使用していく。 ・Models/ApplicationUser.cs using Microsoft.AspNetCore.Identity; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Qiita.Server.Models { public class ApplicationUser : IdentityUser { } } AspNetUsersテーブルにカラムを追加したいときなどに、このファイルに記載する。 ・Startup.cs いろいろな設定を追加したり、依存注入をする際に使用していく。 [Blazor関連のリンク] Blazor WebAssembly プロジェクト作成(認証あり) Blazor WebAssembly 初期プロジェクト構成の入門 Blazor WebAssembly Postgresを使うまで Blazor WebAssembly コードビハインド Blazor WebAssembly InputSelectの使い方
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Blazor WebAssembly プロジェクト作成(認証あり)

はじめに この記事はBlazor WebAssemblyアプリプロジェクトを認証ありでデバック実行しSQLServerを使いアカウントの登録/ログインが出来るまで行うための記事です。「Qiita」という名前で以下の追加情報でプロジェクトを作成しています。 ターゲットフレームワーク NET5.0使っています。デバックはしずらいです。.NET 6.0になるとデバックがしやすくなるだとか。 認証の種類 個別のアカウントしか使った事がありません。 アプリの機能としてログイン機能や認証/承認を行えます。 HTTPS用の構成 基本的に社内環境でしか使わない場合でもHTTPS構成の選択で良いと思います。 ※IISマネージャー上で自己署名入り証明書の作成(簡単)を行うことで無料で即使える状態に出来ます。 ASP.NET Coreでホストされた ソリューション内にBlazor WebAssembly用のプロジェクトと、Blazor WebAssemblyから情報取得する際に使うためのASP.NETcore(WebApi用)のプロジェクトが作成されます。 プログレッシブWebアプリケーション ブラウザによって表示のされ方は違いますが、インストールして使うことが出来ます。 youtubeで使ってみると分かりやすいです。下の図の赤丸でインストールして使えます。 デバック成功までの手順 この時点でデバック実行は正常に動きます。以下の画面が出ていると思います。 しかし、右上のRegisterを押しフォームを入力し更新するとエラーが発生します。 このエラーはアカウントを登録するためDBが無いためエラーが発生しています。 DBのテーブルなどは簡単に作成出来るようになっています。 アカウント情報格納用のテーブルを作成する。 Serverプロジェクト内にあるappsettings.jsonファイルの「DefaultConnection」を変更。 例)"DefaultConnection": "Server=localhost;Database=sample;User ID=sa;Password=password;" パッケージマネージャーコンソールでAdd-Migration InitialMigrationを実行。 本当はこの時点ではしなくても良いが流れ上。Add-Migrationはコードファーストの情報を元にDB変更の情報を作成する。「InitialMigration」は適当な文字列を入力する。 パッケージマネージャーコンソールでUpdate-Databaseを実行。 Add-Migrationで行ったDBの変更情報を元にDBを変更する。 以下のテーブルが自動で作成される。 ・__EFMigrationsHistory : Migrationの実行履歴保存用。この履歴を見て実行されていないMigrationが実行される。 ・AspNetUsers : アカウントの登録ユーザーが保存される。 ・AspNetRoles : アカウントの役割が登録される。 ・AspNetUserRoles : 上記2つの関連付けテーブル ※他は省略 動作確認 先ほど同じくRegister画面でフォームを入力し更新。 以下の画面が表示される。これは本来であれば登録したメールアドレスにメールが送信され、リンクをクリックする事でメールアドレスの確認が完了となるが、現在では実際にメールは送信されないようになっている(コーディングレベル)。「Click here to confirm your account」をクリックする事で確認済となる。 実際にログインして見る。 ログインに成功したらメニューの「Fetch data」にアクセスが可能となる。 [Blazor関連のリンク] Blazor WebAssembly プロジェクト作成(認証あり) Blazor WebAssembly 初期プロジェクト構成の入門 Blazor WebAssembly Postgresを使うまで Blazor WebAssembly コードビハインド Blazor WebAssembly InputSelectの使い方
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

継承.part1

メソッドのオーバーライト 今回は継承の中のメソッドのオーバーライトについて解説したい。 アプリケーションを作っていく中で基底のクラスに定義されたメソッドでは機能が不足しそのままでは利用できない場合も考えられる。 そんなときはvirtualキーワードとoverrideキーワードを使う必要がある。 基底クラスでvirtualキーワードを使いメソッドを定義すると、そのメソッドを派生クラスで上書きすることができる。 class Person //基底クラス { public string FirstName { get; set; } public string LastName { get; set; } public string FullName { get { return LastName + FirstName; } } public string Email { get; set; } public virtual void Print() //virtualキーワードをつけると派生クラスでオーバーライトできる { Console.WriteLine($"名前: {FullName} {Email})"); } } class Employee: Person //派生クラス { public int Number { get; set; } public DateTime HireDate { get; set; } public override void Print() //overrideキーワードでメソッドを上書き定義 { Console.WriteLine($"{Number}:{FullName} {Email} {HireDate.Year}年入社"); } } 基底クラスでvirtualキーワードを使いメソッドを定義すると、そのメソッドを派生クラスで上書きすることができます。 このメソッドオーバーライドと言います。 public virtual void Print() の部分がそれに当たります。 public override void Print() の部分がオーバーライドしている箇所です。 class Program { static void Main(string[] args) { Practice_13_3_2(); } public static void Practice_13_3_2() { var person= new Person { FirstName = "はるか", LastName = "佐々木", Email = "hsasaki@example.com" }; person.Print(); var employee = new Employee { Number = 132, FirstName = "涼太", LastName = "田中", Email = "rtanaka@exmple.com", HireDate = new DateTime(2015, 10, 1) }; employee.Print(); } } 結果は 名前: 佐々木はるか hsasaki@example.com) 132:田中涼太 rtanaka@exmple.com 2015年入社 となります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

以前作ったスクレイピングしてメールを送るバッチ処理アプリをリファクタリングしてみた。

はじめに C#の勉強として以前作ったバッチ処理のコードをリファクタリングしてみました。 以前のコードの問題点 色々ありました・・・ 一つのメソッドに処理をダーッと書いている 資格情報がソースコード上にべた書き ログが残らない これくらいのコード量ならまあ良いかな?とも思ったりするのですが、今回は勉強としてちゃんとフォルダを分けたり、各クラスへ処理を分けてみたりしました。 ソースコード 全体のソースコードは以下です。 一部仕様を変更した 今回のソースコードなのですが、一部仕様を変更しました。 前回書いた処理では1日前に投稿されたトピックのみをメールで送る処理にしていたのですが、スクレイピング先のサイトのバグなのか投稿日付が一部全然違う日付になっていたりしていたので、CSVファイルに1度送ったトピックを保存し、そのCSVファイルにないトピックをメールで送るという内容にしました。 CSVファイルにした理由はデータベースを使うほどの規模ではないかなと思ったからです。 フォルダ構成 元のフォルダ構成 ScrapingApp ├─Program.cs 現在のフォルダ構成 ScrapingApp ├─Config │ ├── MailSettingsConfig.cs │ ├── ScrapingTargetsConfig.cs │ └── StorageConfig.cs ├─Dtos │ ├── Mail.cs │ └── Topic.cs ├─Models │ ├── MailModel.cs │ └── SystemDate.cs ├─Repositories │ ├── GetTopicRepository.cs │ └── ResolveCsvRepository.cs ├─Services │ └── ResolveTopicsService.cs ├─Storages │ └── CSV │ └── Topic.csv ├─appsettings.json ├─Program.cs ├─ScrapingApp.cs ├─Startup.cs 各フォルダについては以下を意識しました。 フォルダ名 意識した点 Config appsettings.jsonの各セクションのマッピング Dtos 利用するデータのオブジェクトたち。※Entityにしようか迷ったのですがデータベース間との通信ではないかなと思ったのでこちらの名前にしてみました Models RepositoriesにもServicesにも当てはまらなさそうなもの Repositories 通信が発生するスクレイピングおよびCSVファイル(今回のデータベース替わり)とのやり取り Services Repositoriesからもらった情報の加工 ソースコードのBeforeとAfter スクレイピングで対象データの取得まで Before Program.cs var urlstring = "スクレイピングしたいサイトのURL"; using var stream = await _client.GetStreamAsync(new Uri(urlstring)); var parser = new HtmlParser(); // 指定したサイトのHTMLをストリームで取得する IHtmlDocument doc = await parser.ParseDocumentAsync(stream); // 以下から★部分までは僕の取得したかった情報を取得するためにセットしている // だけなのでここら辺は取得したい内容によって変わるかと思います。 var tdElements = doc.GetElementById("Id名").QuerySelectorAll("セレクタ"); After Afterではインターフェースを定義してそちらを継承して処理を作りました。 (Unitテストのコードは作っていないですが)これで単体テスト時もMockを使ってテストコードを作ることができます。 またASP.NET CoreアプリケーションにてHttpClientクラスを利用する際はHttpClientFactoryクラスの利用が推奨されているため、そちらを利用しています。 GetTopicRepository.cs public interface IGetTopicRepository { /// <summary> /// スクレイピングで対象のトピックを取得します。 /// </summary> /// <returns></returns> ValueTask<IHtmlCollection<IElement>> GetTopicDataAsync(); } public class GetTopicRepository : IGetTopicRepository { private readonly IHttpClientFactory _clientFactory; private readonly ScrapingTargetsConfig _scrapingTargetsConfig; public GetTopicRepository(IHttpClientFactory clientFactory, IOptions<ScrapingTargetsConfig> scrapingTargetsConfig) { _clientFactory = clientFactory; _scrapingTargetsConfig = scrapingTargetsConfig.Value; } public async ValueTask<IHtmlCollection<IElement>> GetTopicDataAsync() { using var stream = await _clientFactory.CreateClient().GetStreamAsync(new Uri(_scrapingTargetsConfig.Url)); IHtmlDocument doc = await new HtmlParser().ParseDocumentAsync(stream); return doc.GetElementById("Id名").QuerySelectorAll("セレクタ"); } } 取得したデータの加工 Before Program.cs var yearStr = DateTime.Now.Year.ToString(); // メールのBodyに入れる内容をStringBuilderへ入れていきます。 StringBuilder sb = new(); foreach (var tr in tdElements) { // 今回のサイトでは年が表示されていなかったので追加しています。 var dttmText = $"{yearStr}/{tr.QuerySelector("セレクタ").TextContent}"; // 1日前からアプリ実行までの期間内に更新された内容があればメールの本文に追加します。 // 今回はテキストとURL(href)をメールで送ります。 if (DateTime.Now.AddDays(-1).CompareTo(DateTime.Parse(dttmText)) > 0) break; sb.AppendLine($"{tr.QuerySelector("セレクタ").TextContent} 投稿日付:{dttmText}"); sb.AppendLine(tr.QuerySelector("セレクタ").GetAttribute("href")); } After 一部仕様を変更したのでロジックが異なる箇所がありますが・・・ こちらも各メソッドの役割分担をしっかり分けるように意識しました。 Beforeでは直でDateTime.Nowと書いているところもAfterではテスト時にMockが作成できるようにインターフェースを挟んでいます。 ResolveTopicsService.cs public interface IResolveTopicsService { ValueTask<IEnumerable<Topic>> GetSendTargets(); IEnumerable<Topic> FormatRawTopics(IHtmlCollection<IElement> elements); } public class ResolveTopicsService : IResolveTopicsService { private readonly IResolveCsvRepository _resolveCsvRepository; private readonly IGetTopicRepository _getTopicRepository; private readonly ISystemDate _systemDate; public ResolveTopicsService( IResolveCsvRepository resolveCsvRepository, IGetTopicRepository getTopicRepository, ISystemDate systemDate) { _resolveCsvRepository = resolveCsvRepository; _getTopicRepository = getTopicRepository; _systemDate = systemDate; } public IEnumerable<Topic> FormatRawTopics(IHtmlCollection<IElement> elements) { var topicList = new List<Topic>(); var yearStr = _systemDate.GetSystemDate().Year.ToString(); foreach (var element in elements) { topicList.Add(new Topic { Title = $"{element.QuerySelector("セレクタ").TextContent}", CreatedTime = DateTime.Parse($"{yearStr}/{element.QuerySelector("セレクタ").TextContent}"), Url = element.QuerySelector("セレクタ").GetAttribute("href") }); } return topicList; } public async ValueTask<IEnumerable<Topic>> GetSendTargets() { var targets = await _getTopicRepository.GetTopicDataAsync(); return FormatRawTopics(targets).FilterTopicsWithCsv(_resolveCsvRepository.GetTopics()); } } public static class ResolveTopicsExtensions { public static IEnumerable<Topic> FilterTopicsWithCsv( this IEnumerable<Topic> topics, IEnumerable<Topic> targets) { return topics.Except(targets); } } メール送信まで Before Program.cs // ここからはMailKitというライブラリを用いてメールを送る処理を行っています。 var message = new MimeKit.MimeMessage(); message.From.Add(new MimeKit.MailboxAddress("メール送信元の名前", "メール送信元のアドレス")); message.To.Add(new MimeKit.MailboxAddress("メール送信先の名前", "メール送信先のアドレス")); message.Subject = "〇〇通知を送ります~~"; var textPart = new MimeKit.TextPart(MimeKit.Text.TextFormat.Plain) { Text = string.IsNullOrEmpty(sb.ToString()) ? "新規〇〇探しにいったけどなかった(;´∀`)\n無駄にメール送ってごめんねm(__)m" : sb.ToString() }; message.Body = textPart; using var client = new MailKit.Net.Smtp.SmtpClient(); try { await client.ConnectAsync("smtp.gmail.com", 587); await client.AuthenticateAsync("Gmailのメールアドレス", "Gmailのアカウントパスワード"); await client.SendAsync(message); await client.DisconnectAsync(true); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } After こちらも各メソッドの役割分担をしっかり分けるように意識しました。 あとはBeforeではソースコード上にべた書きしていた情報を外部ファイルから呼び出すように変更したりエラー時のログを残すようにしたり等修正しました。 MailModel.cs public interface IMailModel { /// <summary> /// メールを送信します。 /// </summary> /// <param name="mimeMessage"></param> /// <returns></returns> ValueTask SendMail(MimeMessage mimeMessage); /// <summary> /// メール送信に必要な情報を作成します。 /// </summary> /// <param name="mail"></param> /// <returns></returns> MimeMessage CreateMailContext(Mail mail); /// <summary> /// メールの本文を作成します。 /// </summary> /// <param name="htmlCollection"></param> /// <returns></returns> string CreateMailBody(IEnumerable<Topic> topics); } public sealed class MailModel : IMailModel { private readonly MailSettingsConfig _mailSettingsConfig; private readonly ILogger<IMailModel> _logger; public MailModel( IOptions<MailSettingsConfig> mailSettingsConfig, ILogger<IMailModel> logger) { _mailSettingsConfig = mailSettingsConfig.Value; _logger = logger; } public string CreateMailBody(IEnumerable<Topic> topics) { if (!topics.Any()) return _mailSettingsConfig.DefaultResponse; StringBuilder sb = new(); foreach(var topic in topics) { sb.AppendLine($"{topic.Title} 投稿日付: {topic.CreatedTime}"); sb.AppendLine($"{topic.Url}"); sb.AppendLine(); } return sb.ToString(); } public MimeMessage CreateMailContext(Mail mail) { var context = new MimeMessage(); context.From.Add(new MailboxAddress(_mailSettingsConfig.FromName, _mailSettingsConfig.FromAddress)); context.To.Add(new MailboxAddress(_mailSettingsConfig.ToName, mail.To)); context.Bcc.Add(new MailboxAddress(_mailSettingsConfig.BccName, mail.Bcc)); context.Subject = mail.Subject; context.Body = new TextPart(MimeKit.Text.TextFormat.Plain){ Text = mail.Body.ToString() }; return context; } public async ValueTask SendMail(MimeMessage mailContext) { using var client = new MailKit.Net.Smtp.SmtpClient(); try { _logger.LogInformation("メールを送信します。"); await client.ConnectAsync(_mailSettingsConfig.HostName, _mailSettingsConfig.Port); await client.AuthenticateAsync(_mailSettingsConfig.UserName, _mailSettingsConfig.Password); await client.SendAsync(mailContext); await client.DisconnectAsync(true); } catch (Exception ex) { _logger.LogError("メールの送信に失敗しました"); _logger.LogError(ex.Message); _logger.LogError(ex.StackTrace); } } } おわりに 以前、設計系の勉強会に参加した際に「良いコードは"Tell, Don't Ask"が出来ている」という内容をお聞きしました。 "Tell, Don't Ask"は「オブジェクトに対してどのように処理をするのかを聞くのではなく、必要な情報を渡して呼んだら情報が返ってくる」という感じの内容ですが少しは取り入れられたかな?と思っていたりします。 それにしても機能ごとに分けて最後にガシャーンと動作がハマったときの楽しさはヤバいですね(笑) まだまだ半人前なので今回リファクタリングしたコードでもたくさん改善の余地がありそうです。 もっともっと勉強していかねば!!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【C#】文字の抜粋と配列

文字列の抜粋 前提条件 //abcde と入力 string str = Console.ReadLine(); 以降それぞれのパターンを記載します。 配列の中身を抜粋する 前から数えて抜粋 ToCharArray() //インデックス2番目を始点と数え、4つ抜粋する char[] chArray = str.ToCharArray(2, 4); Console.WriteLine(chArray); //cdef str.Substring() //同上別のパターン Console.WriteLine(str.Substring(2, 4)); //cdef SubstringByTextElements() //同上別のパターン using System.Globalization; ...(略) StringInfo str2 = new StringInfo(str); Console.WriteLine(str2.SubstringByTextElements(2, 4)); //cdef 範囲演算子(「..」と表記されているもの) char[] chArray = str.ToCharArray(); //インデックス2番目から3番目までを抜粋する(2以上4未満) Console.WriteLine(chArray[2..4]); //cd 仮に… インデックスじゃなくて、数えでの2番目~4番目を抜粋したい。 範囲演算子「..」を使用しない場合。 数えで2番目から4番目を抜粋(2以上4以下) char[] chArray = str.ToCharArray(2 - 1, 4 - 2 + 1); Console.WriteLine(chArray); //bcd ------------ //入力あり + 計算部分を置き換え int num = int.Parse(Console.ReadLine()); //2 int num_2 = int.Parse(Console.ReadLine()); //4 char[] chArray = str.ToCharArray(num - 1, num_2 - num + 1) //bcd 配列をコピーして抜粋 Array.Copy() char[] chArray = str.ToCharArray(); char [] chArray_copy = new char[6]; //chArray[1]~の中身を、 chArray_copy[2]~[5]にコピー。 //(chArray_copyのインデックス2番目を含んだ、4つ分のインデックスにコピー) //(つまりchArray_copy[2][3][4][5]の位置にコピーする) Array.Copy(chArray, 1, chArray_copy, 2, 4); Console.WriteLine (chArray_copy); //bcde ちなみに、 Array.Copy()では参照元(コピー元)の値が変化しても影響を受けないです。 後ろから数えて抜粋 ^ //後ろから数えて2番目を抜粋 Console.WriteLine(chArray[^2]) ; //d 入力した文字列を1文字ずつ配列に入れる //例:a b c de f と入力 string str = Console.ReadLine(); char[] chArray = str.ToCharArray(); //[a][ ][b][ ][c][ ][d][e][ ][f] 空白ごと入ります。 using System.Linq; ...(略) char[] ch = str.ToArray(); //[a][ ][b][ ][c][ ][d][e][ ][f] また、ToArry()でも同様に配列ができます。 この場合はusing System.Linq;を追加します。 入力した1文字が何番目にあるか探す //例;abcde と入力 string str = Console.ReadLine(); char [] chArry = str.ToCharArray(); //探したい文字をひとつ入力 int str2 = Console.Read(); //b for (int i = 0; i < str.Length; i++) { if ((char)str2 == chArry[i]) { Console.WriteLine(i + 1); //2 } } bという文字が2番目にあることが分かります。 参考にしたサイト String.ToCharArray メソッド StringInfo.SubstringByTextElements メソッド0 インデックスと範囲 Array.Copy メソッド
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C# DateTime.Part1

Datetimeの扱い方 C#でのDateTime型を定義して宣言するときは var employee = new Employee { HireDeta = new DateTIme } 必ずnewをつけるようにしてください。 Datetimeを呼び出す時 var enloy { NUmber = 352, FirstName = "涼太", LastName = "田中", HireDate = new DateTime(2015, 10, 1) }; Console.WriteLine("作業員番号{0}の{1}は、{2}年に入社しました。", employee.Number, employee.FullName, employee.Year); DateTimeの後ろにYearをつけると2015が代入される。Dayだと1、Monthだと10となる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C#の基礎知識 Patt1

Datetimeの扱い方 C#でのDateTime型を定義して宣言するときは var employee = new Employee { HireDeta = new DateTIme } 必ずnewをつけるようにしてください。 Datetimeを呼び出す時 var enloy { NUmber = 352, FirstName = "涼太", LastName = "田中", HireDate = new DateTime(2015, 10, 1) }; Console.WriteLine("作業員番号{0}の{1}は、{2}年に入社しました。", employee.Number, employee.FullName, employee.Year); DateTimeの後ろにYearをつけると2015が代入される。Dayだと1、MOnthだと10となる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

他人のC#のコードの継承元が複雑すぎて、理解できない話

unityとC#初心者が色々触ろうとした結果 今回はunityで他人のgithubから落としたコードを読む際に、継承が多すぎて、どうなっているのかわけわからなくなったという状況に陥りました。 もともと、hololensをunityとROSで連携させたいということで、unityとROSを連携させるROS#というassetを扱っていました。 unity上で、ボタンを押すとROSのほうに簡単なメッセージが出るというようなプログラムをROS#を再利用、改変して作ろうということになりました。 それで、ROS#のプログラムを見たんですが、これが全く読めない。 どこをどのように継承してるのか、わけがわからなくなって、結局改変せずにROSのほうで解決するということになりました。 自分が書いたプログラムはわかるんですが、他人が書いたプログラムは、一つのスクリプトでもきついのに、複数スクリプトまたがって継承されると、全然理解できませんでした。 また、unity独自の型とか使われてたりしていたので、そこでつまづいたりもしました。 そんな状態だったので、改変すると継承の部分でエラーが出て、動きませんでした。 エラーの原因もわからずお手上げでしたね。 C#も、unityも勉強不足 結論としては勉強不足。今回私が扱ったROS#は、かなり読みやすい部類。それでも読めませんでした。 こればっかりは、自分でC#のソフトウェアを色々作ったり、人のプログラムを多く読んで慣れて勉強していかないとなと思いました。 読めるようになったら、どこで躓いてたのか、どう考え方を変えたら読めるようになったかとか、読むコツとかの記事を書ければと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む