ここで問題が何であるかを理解するのに少し問題があります。 LINQを使用してデータベースからレコードをプルし、それらをインターフェイスにキャストされるオブジェクトに入れるコードを少し持っています。次のようになります。
public IEnumerable<ISomeObject> query()
{
return from a in dc.SomeTable
select new SomeObject
{
//Assign various members here
} as ISomeObject;
}
これをテストするとき、返されたIEnumerableをresultsという変数に入れて、次の行を実行します。
Assert.AreEqual(EXPECTED_COUNT, results.Count());
これを実行すると、System.Security.VerificationException: "操作によってランタイムが不安定になる可能性があります。"が発生します。
私は解決策を見つけました here 、これはこれです:
var results = from a in dc.SomeTable
select new SomeObject
{
//Assign various members here
} as ISomeTable;
return results.OfType<ISomeObject>();
これは機能しますが、ここで何が起こっているのか理解できません。なぜ最初に例外が発生したのですか?上記のコード行はどのようにしてそれを修正しましたか? MSDNドキュメントは、これがタイプセーフの問題であることを示唆しているようですが、以前のコードがタイプセーフではなかった場所はわかりません。
[〜#〜] update [〜#〜]私が見つけたもう少しの情報。最初の例は、戻り値の型をIQueryableにすると機能します。これはwhatがうまくいかなかったことについてもう少し詳しく説明しますが、whyについてはまだ混乱しています。コンパイラがIEnumerableをIQueryableにキャストするように強制しなかったのはなぜですか?
このフォーラムの投稿 で指摘されているように、それは共分散または反分散の問題であると私は信じています。
Eric Lippertのブログにある C#の共分散と反変、第2部:配列共分散 と残りの 共分散と反変シリーズ を参照してください。
私がリンクした記事で彼は配列を扱っていますが、同様の問題がここにあると思います。最初の例では、IEnumerable
よりも大きいインターフェースを実装するオブジェクトを含むISomeTable
を返します(つまり、タートルをそのIEnumerableがキリンのみを含むことができる場合の動物IEnumerable)。 IQueryable
を返すときにそれが機能する理由は、それが返すことができるものよりも大きい/広いなので、何を返すかが保証されるからですあなたは処理することができます(?)。
2番目の例では、 OfType は、Giraffeにキャストできる要素のみを返すために必要なすべての情報を格納するオブジェクトが返されることを保証しています。
上で概説したタイプセーフティの問題とは関係があると確信していますが、Eric Lippertが言うように 高次関数は脳を傷つけます これがco /である理由を正確に表現するのに苦労しています/反変問題。
「操作によってランタイムが不安定になる可能性がある」という自分の解決策を探しているときに、このエントリを見つけました。上記の共分散/逆分散のアドバイスは非常に興味深いように見えますが、結局、コードカバレッジをオンにしてAllowPartiallyTrustedCallersアセンブリ属性を設定してユニットテストを実行すると、同じエラーメッセージが表示されることがわかりました。
AllowPartiallyTrustedCallers属性を削除すると、テストが正常に実行されました。コードカバレッジをオフにして実行することもできましたが、それは許容できる解決策ではありませんでした。
うまくいけば、これがこのページへのアクセスを試みた他の誰かがこの問題の解決策を見つけようとするのを助けるでしょう。
推測だけですが、as演算子はnullを返す可能性があります。そのため、_new SomeObject { ... }
_コードの実際の実装と関係がある可能性があります。 return results.OfType<ISomeTable>();
はタイプに基づいてフィルタリングするため、メソッドのreturnステートメントはそのタイプのみを返します(タイプセーフを保証します)。私はジェネリック型を返すことで同様の問題に遭遇しました。
追伸「操作によってランタイムが不安定になる可能性があります。」例外。これは、「インターネットを爆破するかもしれない」という例外とほとんど同じです。
私は同様のコードでこのエラーに遭遇しました。
IEnumerable<Table> records = (from t in db.Tables
where t.Id.Equals(1)
select t).ToList();
この一見無害なコードは、ページから呼び出されたUserControlメソッドの一部でした。 .NET4開発環境では問題ありませんが、サイトがプリコンパイルされ、.NET3.5上のサーバーにデプロイされると、このエラーが発生しました。
これは、コントロールが別のDLLで説明されているように、フレームワーク間のセキュリティ変更と組み合わされてコンパイルされていたという事実に関係していると思います この.NETセキュリティブログ
私の解決策:.NET4でライブサイトを実行する
同じ問題がありましたが、継承により、以下の属性をアセンブリAに追加した後、アセンブリAのクラスとアセンブリBのサブクラスを定義し、問題を解決しました。
[Assembly: SecurityRules(SecurityRuleSet.Level1, SkipVerificationInFullTrust = true)]
Linq to sqlを使用すると、OfTypeにいくつかの厄介な副作用があることがわかりました。たとえば、dbに対してクエリを実行した後に以前に評価されたlinqの一部は、代わりにSQLに変換されました。これらのセクションには同等のSQLがないため、これは失敗しました。代わりに.Castを使用することになり、問題も解決したようです。
これを変更しても失敗しますか?
select new SomeObject { ... } as ISomeTable;
これに:
select (ISomeTable) new SomeObject { ... };
?
もしそうなら(あなたが確認したように)、おそらくこれはインターフェース実装がクラスか構造体のどちらかであるという事実に関係しているのでしょうか?インターフェースではなく抽象クラスにキャストした場合でも問題は発生しますか?
「ダイナミックデータアクセスフレームワーク」を使用しているときにこのエラーに遭遇しました パッシブライブラリ 。エラーの原因は、DynamicDatabase.csファイルの100行目でした。
databaseDetectors = (databaseDetectors ?? Enumerable.Empty<DatabaseDetector>()).DefaultIfEmpty(new DatabaseDetector());
そのコード行を次のように変更しました:
databaseDetectors = (databaseDetectors ?? Enumerable.Empty<DatabaseDetector>()).DefaultIfEmpty(new DatabaseDetector()).OfType<IDatabaseDetector>();
これで問題は解決しました。私は先に進んで プロジェクトを分岐した とし、変更を元の作者に提出しました。
元の質問で解決策を指摘してくれたJason Bakerに感謝します。
余談ですが、元のライブラリはローカルマシンとRackspace VPSで正常に動作しましたが、同じコードを共有ホスティング環境(GoDaddyとRackspaceのクラウドサイト)にプッシュすると、「操作によってランタイムが不安定になる可能性があります"エラー。
`セクションのweb.configファイルにSystem.Security.VerificationExceptionを追加しました:「操作によりランタイムが不安定になる可能性があります。」私のために来ない。
<system.Web>
<trust level="Full"/>
私の場合、Linq2SQLクラスのColumn属性でStorageプロパティを誤って宣言しました
[Column(Storage = "_Alias", DbType = "NVarChar(50)")]
public string UserAlias