0

アプリケーション内の C# スクリプトで使用するカスタム型システムを作成しました。スクリプトはオンザフライでコンパイルされ、アプリケーションの内部データとの対話を可能にします。この型システムは、 のようなインターフェイスを使用して抽象的な方法で設計されていますIValue。の実装は, ,であるIValue可能性があります(他の多くの中でも、これは私の問題を実証するのに十分です)。RefStringRefIntegerRefDouble

ここで行き詰まるところまで来ました... これらのIValueオブジェクトの使用はやや不自然です。常にインターフェイスを使用してオブジェクトと対話することは適切な設計と見なされますが、暗黙的な変換を定義したり、インターフェイスの演算子をオーバーロードしたりする可能性はありません。これは、適切な演算子が使用されるように、醜い明示的なキャストが避けられない状況につながります。

例:

IValue Add(IValue a, IValue b)
{
    //return a+b; // won't work: which operator +() to use?
    return (RefInteger)a + (RefInteger)b;
}

値型を含む式の C# の場合、暗黙的な変換が提供されます。このようなカスタム システムを設計するにはどうすればよいでしょうか?

型システムを書き直して、インターフェイスを削除し、基本クラスIValueを導入しました。RefValueこのようにして、すでに明示的なキャストの一部を削除できます。この基本クラスにいくつかの演算子のオーバーロードを実装しましたが、デフォルトの変換演算子で多くの問題が発生しました...これに加えて、演算子の実装で実装するロジックには、システムの型に関する多くの知識が関係しています。これはどういうわけかまだ行かなければならない方法だと思いますが、これを適切かつ安全な方法で実装するために従うべきルールは何ですか?

編集:しばらく苦労した後、私が見つけることができたルールのいくつかは次のとおりです。

  • 基本型 (int、double、string など) からの変換演算子のみを暗黙的に宣言します。
  • 基本型への変換を明示的に宣言します (int への暗黙的なキャストを避けるため!! よくあることですが、なぜでしょうか?)
  • あいまいな呼び出しを避けるために、+、-、/、* 演算子を基本クラスと派生クラスでオーバーライドしないでください。【その後の行き方は?派生クラスで操作のオーバーロードを行いましたが、これには使用時にキャストが必要であり、これもまた醜いです...]
4

1 に答える 1

1

Addすべての に対して操作を行うことができると想定されている場合IValue、おそらくインターフェイスにメソッドを含める必要がありますAddか? return a.Add(b);次に、操作を実行する方法の知識を各タイプにプッシュすることができます。

a問題の 1 つは、現在のように、 isRefStringbisの場所で呼び出しを受ける可能性がRefIntegerあることです。これは、おそらく望んでいるものではありません。ジェネリックはそれを修正するのに役立ちます:

T Add<T>(T a, T b) where T : IValue
{
    return a.Add(b);
}

(もちろん、適切なnullチェックなどを追加する必要があります)

于 2010-11-01T19:26:42.370 に答える