XORveR.com の日記

XORveR.com の公式ブログです。

標準ではない文字列リソース管理でときどきしくじる。後悔したので対策を取った。

まえがき

いらいらして標準でない文字列リソース管理をやった。全く後悔していない。 での String.cs を T4 で json 化する方式は問題なく動いています。
しかし、コーディングしている当人は問題なく動いていません。

ええ、public const string PropertyName = "OtherName"; とかミスるんですね、これが!

対策案1

Linqのクエリ式を使ったプロパティ名の記述の、ひどい使い方について での方法で、自分のフィールド名を文字列として設定する。

対策案1の結果

役立たないので、特にコードは不詳とします。

System.Exception はユーザー コードによってハンドルされませんでした。
  HResult=-2146233088
  Message=Template runtime error
  Source=TemporaryT4Assembly
  StackTrace:
       場所 Microsoft.VisualStudio.TextTemplating9E8AB61775526334C6D46ECC568F9EA900D98271D962C359E9D3B07FCA9DECDD048F8A79972FBF5F11EAA24C870BA3F8B009EF637F402FB1D214E97D4F72BED5.GeneratedTextTransformation.TransformText() 場所 D:\usr\vs2015\XORveR\XORveR_FP\Resources\Strings.en-US.tt:行 40
       場所 System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
       場所 Microsoft.VisualStudio.TextTemplating.TransformationRunner.PerformTransformation()
  InnerException: 
       FileName=file:///C:\Users\アカウント名\AppData\Local\Temp\twhymmjk.dll
       FusionLog==== 事前バインド状態情報 ===
ログ: Where-ref バインドです。場所 = C:\Users\アカウント名\AppData\Local\Temp\twhymmjk.dll
ログ: Appbase = file:///D:/Program Files (x86)/Microsoft Visual Studio 14.0/Common7/IDE/
ログ: Initial PrivatePath = NULL
呼び出しているアセンブリ: (Unknown)
===
ログ: このバインドは LoadFrom の読み込みコンテキストで開始します。
警告: ネイティブ イメージは LoadFrom コンテキストで調査されません。ネイティブ イメージは、Assembly.Load() を使用するなどの既定の読み込みコンテキストでのみ調査されます。
ログ: アプリケーション構成ファイル D:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\T4VSHostProcess.exe.Config を使用します。
ログ: ホスト構成ファイル  を使用します。
ログ: C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config からのコンピューター構成ファイルを使用します。
ログ: 新しい URL file:///C:/Users/アカウント名/AppData/Local/Temp/twhymmjk.dll をダウンロードしようとしています。

       HResult=-2147024894
       Message=ファイルまたはアセンブリ 'file:///C:\Users\アカウント名\AppData\Local\Temp\twhymmjk.dll'、またはその依存関係の 1 つが読み込めませんでした。指定されたファイルが見つかりません。
       Source=mscorlib
       StackTrace:
            場所 System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
            場所 System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
            場所 System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
            場所 System.Reflection.Assembly.Load(AssemblyName assemblyRef, Evidence assemblySecurity)
            場所 System.CodeDom.Compiler.CompilerResults.get_CompiledAssembly()
            場所 Microsoft.VisualStudio.TextTemplating9E8AB61775526334C6D46ECC568F9EA900D98271D962C359E9D3B07FCA9DECDD048F8A79972FBF5F11EAA24C870BA3F8B009EF637F402FB1D214E97D4F72BED5.GeneratedTextTransformation.TransformText() 場所 D:\usr\vs2015\XORveR\XORveR_FP\Resources\Strings.en-US.tt:行 17
       InnerException: 

orz...

T4 でのコンパイラでは、クエリ式使ったソースだからなのか?
もしくはstatic変数をコードで設定するようなクラスだからなのか?
ともかく、そのアセンブリは生成できない模様。

コンパイラのオプションで v4.0 とか色々指定してみたけど、ダメでした。
コンパイル時の参照アセンブリとかも指定しないからダメなのかも?
T4 実行時の名前空間には System.Linq.Expressions も追加してみたり。

そもそも T4 スクリプトの修正はとっても面倒そう。

対策案2

ハッと気づく私。
単体テストでチェックすれば良かっただけでした。

using System;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace XORveR.I18n.Tests {
    [TestClass()]
    public class MessageAttributeTests {
        [TestMethod()]
        public void MessageAttributeTest() {
            Type type = typeof(Strings);
            Type att = typeof(MessageAttribute);
            PropertyInfo Message = att.GetProperty("Message");
            PropertyInfo IsSeparate = att.GetProperty("IsSeparate");
            foreach (FieldInfo field in typeof(Strings).GetFields()) {
                var mesatt = field.GetCustomAttribute(att);
                var message = (string)Message.GetValue(mesatt);
                var isseparate = (bool)IsSeparate.GetValue(mesatt);
                var value = field.GetValue(null);
                Assert.AreEqual(field.GetValue(null), field.Name);
            }
        }
    }
}

全力で空回りしている感が強いです。

では!