16
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

東京理科大学Advent Calendar 2017

Day 4

「強いエンジニアにHelloWorldさせてみた(縛りあり)」をC#でやってみた

Last updated at Posted at 2017-12-17

はじめに

自分のブログにアップするつもりで、この記事を書いたのですが、せっかくなので、アドベントカレンダーに参加したいと思います。

でも、C#のアドベントカレンダーはすでにいっぱいです。それで、色々と調べていたら「東京理科大学 Advent Calendar 2017」というのがあるではないですか。
すでに、理工学部・情報科学科を卒業してから、30年以上の歳月が経ってしまいましたが、OB,OG可ということなので、空いている12月4日の記事としてアップさせていただくことにしました。

これまでアップされている記事を見ると、C#という言語がかなり異端っぽい気がしますが、そこは許してください。

元ネタ

強いエンジニアにHelloWorldさせてみた(縛りあり)

ここで取り上げられている問題を引用してみると

ソースコードにダブルクォート、シングルクォート、数字を書くこと無く、「LIFULL」と出力して下さい。
最後に改行を付けること。
言語は問いません。

ということです。

C#でもやってみよう!

「ダブルクォート、シングルクォート、数字を書くこと無く」というのがいやらしいですね。

これをC#でいくつかのやり方で解いてみました。ただ、「LIFULL」ではなく、出力する文字列は、「HelloWorld」に変更します。

結構、いろんなやり方がありました。

nameof演算子を使うやり方

たぶん、これが一番簡単な方法だと思います。

using System;

class HelloWorld {
    static void Main(string[] args) {
        Console.WriteLine(nameof(HelloWorld));
    }
}

classの名前を'HelloWorld'にして、そのクラス名をnameof演算子で取り出しています。
nameof演算子は、C#6.0以降で利用できる演算子です。なので、C#5.0以前のバージョンでは利用できません。

リフレクションを使う (1)

次に簡単だと思われるとが、TypeクラスのNameプロパティを使う方法でしょうか。

using System;

class HelloWorld {
    static void Main(string[] args) {
        Console.WriteLine(typeof(HelloWorld).Name);
    }
}

これも、クラス名を HelloWorldにしています。これならば、C#5.0以前でもOKです。

リフレクションを使う (2)

もう一つ、リフレクションを使う例です。

using System;
using System.Linq;
using System.Reflection;

class Program {
    public static string HelloWorld { get; set; }
    static void Main(string[] args) {
        var n = typeof(Program).GetProperties(BindingFlags.Public | BindingFlags.Static).First().Name;
        Console.WriteLine(n);
    }
}

これは、クラス名ではなく、プロパティ名をリフレクション使って取得しています。GetPropertiesメソッドの戻り値は配列なので、先頭の要素を取得するのに、LINQのFirstメソッドを使っています。[0]は数字使うのでアウトです。

CallerMemberName属性を使う

C#5.0で導入されたCallerMemberName属性を使ってもできますね。

using System;
using System.Runtime.CompilerServices;

class Program {

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

    static void HelloWorld() {
        Print();
    }

    static void Print([CallerMemberName] string member = null) {
        Console.WriteLine(member);
    }
}

だんだん、複雑なコードになってきました。CallerMemberName属性使うと、呼び出し元のメソッド名を引数として受け取れるので、HelloWorldというメソッドを定義し、そこからPrintメソッドを呼び出すことで、Printメソッドの中で、文字列"HelloWorld" を取得できるというわけです。

リフレクション使わずに強引にやる

最後は、本当に強引な方法です。

System.Windows.Forms名前空間に定義されているKeys列挙型を使って、”HelloWorld”を組み立てています。
途中LINQ使ってますが、LINQは必須ではないので、書き換えれば、C#2.0でも動くプログラムにすることができると思います。

""も使えないので、String.Empty使ってます。

なお、他のコードは、.NET Coreでも動作しますが、このコードだけは、.NET Coreだと動きません。

using System;
using System.Linq;
using System.Windows.Forms;

class Program {
    static void Main(string[] args) {
    
        string CreateString(Keys[] keys) {
            int index = String.Empty.Length; // 0をセット
            return keys.Aggregate(String.Empty, (s, k) => { 
              return s + (index++ == String.Empty.Length ? k.ToString() : k.ToString().ToLower()); 
            });
        }
        
        var hello = new Keys[] { Keys.H, Keys.E, Keys.L, Keys.L, Keys.O };
        Console.Write(CreateString(hello));
        var world = new Keys[] { Keys.W, Keys.O, Keys.R, Keys.L, Keys.D };
        Console.WriteLine(CreateString(world));
    }
}

最後に

結構、いろんなやり方がありましたね。こういった縛りのある問題をとくと、言語の持つ機能を理解するのに大いに役立ちますね。
CallerMemberName属性は、その存在は知っていましたが、ほとんど使ったことがなかったので、勉強になりました。

16
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?