で拡張メソッドを作成できますResourceManager
。
public static class ResourceExtensions
{
public static MemoryStream GetMemoryStream(this ResourceManager resourceManager, String name) {
object resource = resourceManager.GetObject(name);
if (resource is byte[]) {
return new MemoryStream((byte[])resource);
}
else {
throw new System.InvalidCastException("The specified resource is not a binary resource.");
}
}
}
呼び出し
ResourceManager resourceManager = Properties.Resources.ResourceManager;
MemoryStream stream = resourceManager.GetMemoryStream("binaryResource");
しかし、これも同様のようです。
MemoryStream stream = new MemoryStream(Properties.Resources.SomeBinaryResource);
リソースファイルは変更が難しいため、変更するかどうかはわかりません。また、VisualStudioが変更を上書きするシナリオがあると確信しています。
これに関する問題は、あなたの懸念によると、これがデータのコピーをメモリに作成し、メモリフットプリントを作成することです。短命である軽量リソースの場合、それは問題ではありませんが、それは大きな懸念事項になる可能性があります。
答えは短いです。を使用してメモリフットプリントを回避することはできませんResourceManager
。問題は、両方ResourceManager.GetObject(String)
とResourceManager.GetStream(String)
データのコピーを作成することです。GetStream(String)
を返しますが、UnmanagedMemoryStream
実際にはGetObject(String)
内部を呼び出し、コピーは作成されたままです。アプリケーションをデバッグしてメモリのプロファイルを作成すると、メモリがまだ割り当てられていることがわかります。
コンテキストでポインターを使用してこれを回避するための複数の方法を試しましたがunsafe
、リフレクションでは何も機能しませんでした。ResourceManager
それほど柔軟でも最適化されていません。
解決策を見つけることができましたが、を使用する必要がありますEmbedded Resources
。Embedded Resource
これは、リソースファイルのビルドアクションをに設定する以外は何も変更しませんBuild Action
。これを使用すると、リフレクションを使用してUnmanagedMemoryStream
、データのコピーを作成しないを作成できます。
private UnmanagedMemoryStream GetUnmanagedMemoryStream(String embeddedResourceName) {
Assembly assembly = Assembly.GetExecutingAssembly();
string[] resourceNames = assembly.GetManifestResourceNames();
string resourceName = resourceNames.SingleOrDefault(resource => resource.EndsWith(embeddedResourceName, StringComparison.InvariantCultureIgnoreCase));
if (resourceName != null) {
return (UnmanagedMemoryStream)assembly.GetManifestResourceStream(resourceName);
}
else {
throw new System.ArgumentException("The specified embedded resource could not be found.", "embeddedResourceName");
}
}
私はこれを広範囲にテストしませんでしたが、動作します。私のテストデータは17メガバイトの小さなファイルでした。テストアプリケーションのワーキングセットメモリは約50メガバイトで始まり、リソースをストリームに取得した後も変更されません。これを使用するResourceManager
と、リソースのサイズだけワーキングセットがすぐに増加します。
EndsWith
リソースの名前は、を介して直接アクセスする場合とは少し異なるため、マニフェストで適切なリソース名をチェックする呼び出しを交換する必要がありResourceManager
ます。
私は実際に既存のものを使用して解決策を見つけることができなかったことに失望していますResourceManager
が、それは単に十分な柔軟性がありません。
編集私はこの主題についてここに詳細なブログ記事を書きました。