Rake、.NET、COM、および動的

住んでいた-古代の恐竜時代のコードでした



与えられた: 地獄は 、同じ「ああ何」製品の16の異なるバージョンで働くコーダーです。 COM、相互運用性、インターフェース、実装、要因のあるシグナルトーン、アンチパターンのあるパターン、モジュール、およびオープンソースのその他の欠陥。 標準セット。 彼は成長し、夫となり、そのkodniknikを7年熟成させました。 これまで、別の修正で16モジュールの一括コピー/貼り付けが修正されませんでした。 誰もが興味を持っている場合-変更のためにforeach on



苦しんだ後、私たちは研究を行いました。 コピーと貼り付けは95%同一であり、相互運用機能からのパッケージの名前のみが異なります。



ラッパーで何百もの関数をラップしないように、またこれらのラッパーのパンチング/ボクシングハンドルをラップしないように書くことは可能ですか?



動的キーワードがあります!





そして、そのような素晴らしい眺めの地獄のパスタ

標準的な恐怖
public abstract class Application : IDisposable { public abstract void Close(); public abstract Document CreateDocument(); public abstract Document OpenDocument(string doc_path); //  200  //    ,     void IDisposable.Dispose() { Close(); } } public class ClientApplication : Application { protected ClientApplication(){ string recovery_path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); recovery_path = Path.Combine( recovery_path, String.Format( @"...\Version {0}\en_GB\Caches\Recovery", Version)); try { foreach (string file in Directory.GetFiles(recovery_path)){ try { File.Delete(file); } catch { } } } catch {} //       } public override void Close() { if (Host != null) { Marshal.ReleaseComObject(Host); Host = null; } } } public class ClientApplication7_5 : ClientApplication { protected ClientApplication7_5() { Type type = Type.GetTypeFromProgID("....Application." + Version, true); _app = Activator.CreateInstance(type) as Interop75.Application; Host = app; // ... } public override Document CreateDocument() { return new ClientDocument7_5(this, _app.Documents.Add()); } public override Document OpenDocument(string doc_path) { return new ClientDocument7_5(this, _app.Open(doc_path, true, ...) as Interop75.Document); } //   200  public override ComObject Host { get { return _app; } set { _app = value as Interop75.Application; } } private Interop75.Application _app; //      -   } public class ServerApplication : Application { public ServerApplication() {} ... } //        ,  8 
      
      





不要になり、この不名誉を使用したコード



 var app = Factory.GetApplication(); var doc = app.Documents.Add(); doc.DocumentPreferences.PreserveLayoutWhenShuffling = false; doc.DocumentPreferences.AllowPageShuffle = true; doc.DocumentPreferences.StartPageNumber = 1;
      
      







変わりません。



利益? やれやれ! 半ば生成されたホラー映画のダースメガバイトは、ゴミ箱に正常にスローされます。 新しいバージョンのサポートは大幅に簡素化されています。



リトアニアの休日「オブロマチス」



テストを実行します。 バム!



そのcom睡状態のすべての呼び出しがOKを返すまで、それは非常にうまくいきません。 しかし、テストを待つ価値があった



 try { var app = Factory.GetApplication(); var doc = app.Documents.Add(); doc.DocumentPreferences.PreserveLayoutWhenShuffling = false; doc.DocumentPreferences.AllowPageShuffle = true; doc.DocumentPreferences.StartPageNumber = -1; } catch (COMException ok) { .... //         "" } catch(Exception bad) { ... //   ,  bad -  NullReferenceException  StackTrace!!! }
      
      







ショック、スキャンダル、陰謀、調査。 誰もが興味を持っている場合-マイクロソフトで確認されたバグは5.0以前に修正されます。 悲しいと退屈。



探究心は休息を与えません-結局、あなたがinteropesを通過するならば、それはすべてあるべきですか? デバッガーは、ドキュメントの種類をSystem .__ ComObjectとして表示します。 しかし、RCWはどうですか? 理解できませんでしたか?



テストを変更します



 try { var app = Factory.GetApplication(); var doc = app.Documents.Add() as Interop75.Document; doc.DocumentPreferences.PreserveLayoutWhenShuffling = false; doc.DocumentPreferences.AllowPageShuffle = true; doc.DocumentPreferences.StartPageNumber = -1; } catch (COMException ok) { .... //       } catch(Exception bad) { ... }
      
      





そして...テストに合格しました。



仮説は興味深いです。 それで、タイプが分からないのではないでしょうか? 確認する



  var app = Factory.GetApplication(); var doc = app.Documents.Add(); var typeName = Microsoft.VisualBasic.Information.TypeName(doc);
      
      





うーん かなり自分自身に。



アイデアは終わりました。



しかし、待ってください-生はありますか? 私たちは見て、喫煙し、難読化のスキルを賞賛します。 ここから開始: __ComObject ここにシームレスに流れました: Type.cs。 出来上がり 喫煙の過程で理解が得られました。したがって、明らかにこれらのas睡状態をさまざまな方法で処理している場所がいくつかあります。 交換するとどうなりますか



 doc.DocumentPreferences.StartPageNumber = -1;
      
      









 Type type = doc.DocumentPreferences.GetType(); type.InvokeMember("StartPageNumber", BindingFlags.SetProperty, null, doc.DocumentPreferences, new object[] { -1 });
      
      





理論的には-何も?



小間物と枢機inalは力です



そして、ここで変化しています。 テストに再び合格しました。 そして何をすべきか? このような美しいコードをパスタに変えても笑顔になることはなく、たくさんあります。



夕方遅く、私は状況を密かにトロールして鎮圧しようとしています-反射神経のスピーカーの認識をスリップできますか? 私はまだ考えを理解しています-そして、これは考えです!



やってみます。



ComWrapperはDynamicObjectを拡張します
 public class ComWrapper : DynamicObject { public ComWrapper(object comObject) { _comObject = comObject; _type = _comObject.GetType(); } public object WrappedObject { get { return _comObject; } } //     //    +  public override bool TryGetMember(GetMemberBinder binder, out object result) { result = Wrap(_type.InvokeMember(binder.Name, BindingFlags.GetProperty, null, _comObject, null)); return true; } public override bool TrySetMember(SetMemberBinder binder, object value) { _type.InvokeMember( binder.Name, BindingFlags.SetProperty, null, _comObject, new object[] { Unwrap(value) } ); return true; } //       public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { result = Wrap(_type.InvokeMember( binder.Name, BindingFlags.InvokeMethod, null, _comObject, args.Select(arg => Unwrap(arg)).ToArray() )); return true; } //    -  private object Wrap(object obj) { return obj != null && obj.GetType().IsCOMObject ? new ComWrapper(obj) : obj; } private object Unwrap(object obj) { ComWrapper wrapper = obj as ComWrapper; return wrapper != null ? wrapper._comObject : obj; } //        +        private object _comObject; private Type _type; }
      
      







素晴らしい-それはそれ自体ですべてを行い、正常に機能します。必要なのは、それらをFactory.GetApplication()の結果でラップすることです。 すぐそこにラップ。 本当にニュアンスがあります-コレクションを忘れてしまいました。 それで少し後に彼らはこれを追加しました:



いくつかのバックアップ
 //     private IEnumerable Enumerate() { foreach (var item in (IEnumerable)_comObject) yield return Wrap(item); } //   enumerable public override bool TryConvert(ConvertBinder binder, out object result) { if (binder.Type.Equals(typeof(IEnumerable)) && _comObject is IEnumerable) { result = Enumerate(); return true; } result = null; return false; } //      ,  .    public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) { if (indexes.Length == 1) { dynamic indexer = _comObject; result = Wrap(indexer[indexes[0]]); return true; } result = null; return false; } public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) { if (indexes.Length == 1) { dynamic indexer = _comObject; indexer[indexes[0]] = Unwrap(value); return true; } return false; }
      
      







今が勝利です。



突然誰かが重宝します。



All Articles