C#でローカル変数の再代入をしたくないない病

関数型言語の影響で、「ローカル変数の再代入をしたくないない病」を発症中です。症状は、C# で開発していると初期化済みのローカル変数を読み取り専用にしたくなります。でも、C# の const は定数でしか使えないし、readonly はローカル変数には使えません。この病の治療法は見つかってないのか…?!


そんなノリで、ローカル変数を読み取り専用にする方法が無いか調べてみたら、以下の記事を発見!

LINQ の let を駆使した技ですね。let で定義した範囲変数は再代入できないという性質を巧みに利用しています。LINQ の中でしか参照できないのが難点ですけど。


試しに、この技を使って WCF の簡単なサンプルを書いたのがこちら。

using System;
using System.Linq;
using System.ServiceModel;

namespace ReadonlySample
{
    [ServiceContract]
    public interface IGreetingService
    {
        [OperationContract]
        string Greet(string name);
    }

    public class GreetingService : IGreetingService
    {
        public string Greet(string name)
        {
            return string.Format("Hello,{0}.", name);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var query = (
                from _ in Enumerable.Range(0, 1)
                let address = "net.pipe://localhost/Greet"
                let host = new ServiceHost(typeof(GreetingService))
                let binding = new NetNamedPipeBinding()
                let endpoint = host.AddServiceEndpoint(typeof(IGreetingService), binding, address)
                let openHostFunc = new Func<ServiceHost>(() =>
                {
                    host.Open();
                    return host;
                })
                let openedHost = openHostFunc()
                let channel = ChannelFactory<IGreetingService>.CreateChannel(binding, new EndpointAddress(address))
                let message = channel.Greet("Ichiro")
                let closeChannelFunc = new Func<IGreetingService>(() =>
                {
                    ((IClientChannel)channel).Close();
                    return channel;
                })
                let closedChannel = closeChannelFunc()
                let closeHostFunc = new Func<ServiceHost>(() =>
                {
                    host.Close();
                    return host;
                })
                let closedHost = closeHostFunc()
                let printFunc = new Func<string>(() =>
                {
                    Console.WriteLine(message);
                    return message;
                })
                let output = printFunc()
                select _
            ).First();

            Console.ReadLine();
        }
    }
}

うん。
変態コードですね!
値を返さないメソッドを呼び出すために Func を使っているあたりなんて特に。


仕事でこんなコードを書こうものなら、コードレビューでフルボッコです。。。C# の readonly をローカル変数でも使えるようになるのが一番いいよなぁ。