gpt4 book ai didi

c# - 如何从包含其程序集和来自任何程序集的路径的 Uri 加载资源?

转载 作者:太空宇宙 更新时间:2023-11-03 19:03:03 24 4
gpt4 key购买 nike

我想仅使用其 uri 从(同一应用程序的)任何程序集加载任何资源。两个程序集都是同一应用程序的一部分。

因为我希望能够从任何程序集加载,所以我不能使用未在通用 Dll 中定义的“App”或“Application”。

我认为部分或答案是使用:System.Reflection.Assembly.GetCallingAssembly().GetManifestResourceStream(path);

但我找不到如何从 uri 中正确查找/提取/解析程序集?

注意事项:

  • 资源实际定义为“Resource”。
  • 资源不是 WPF 资源字典的一部分。
  • 资源实际上是一个 XML 文件,但可以是任何内容

到现在(~3小时后),使用反射器后,似乎使用static System.Windows.Application.GetResourceStream(uri).Stream 具有资源缓存等优势。它很糟糕,因为它与 WPF (System.windows) Hook 。我正在寻找一种更好的方法(不依赖于任何特定的 UI 框架)来完成这项工作。

最佳答案

我用下面定义的这个“LoadResourceFromUri”函数解决了我的问题。我已经在 GitHub 完成并发布了一个项目带有加载任何模块 (dll) 并显示其资源的工具。还可以获得关于 uri 的信息。

byteArray转stream时关于4的偏移,我用了Microsoft code因为否则(没有偏移量),它就不会按预期工作。

enter image description here

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Resources;

namespace HQ.Util.General
{
public static class ResourceHelper
{
// ******************************************************************
/// <summary>
/// The resource should be defined as 'Resource' not as 'Embedded resource'.
/// </summary>
/// <param name="resourcePath">The resource path</param>
/// <param name="assembly">If null, then use calling assembly to find the resource</param>
/// <returns></returns>
public static Uri GetLocationUri(string resourcePath, Assembly assembly = null)
{
if (assembly == null)
{
assembly = Assembly.GetCallingAssembly();
}

resourcePath = resourcePath.Replace('\\', '/');

return new Uri(@"pack://application:,,,/" + assembly.GetName().Name + ";component" +
(resourcePath[0] == '/' ? resourcePath : "/" + resourcePath), UriKind.Absolute);
}

// ******************************************************************
/// <summary>
/// Will load resource from any assembly that is part of the application.
/// It does not rely on Application which is specific to a (UI) frameowrk.
/// </summary>
/// <param name="uri"></param>
/// <param name="asm"></param>
/// <returns></returns>
public static Stream LoadResourceFromUri(Uri uri, Assembly asm = null)
{
Stream stream = null;

if (uri.Authority.StartsWith("application") && uri.Scheme == "pack")
{
string localPath = uri.GetComponents(UriComponents.Path, UriFormat.UriEscaped);

int indexLocalPathWithoutAssembly = localPath.IndexOf(";component/");
if (indexLocalPathWithoutAssembly == -1)
{
indexLocalPathWithoutAssembly = 0;
}
else
{
indexLocalPathWithoutAssembly += 11;
}

if (asm != null) // Take the provided assembly, do not check for the asm in the uri.
{
stream = GetAssemblyResourceStream(asm, localPath.Substring(indexLocalPathWithoutAssembly));
}
else
{
if (uri.Segments.Length > 1)
{
if (uri.Segments[0] == "/" && uri.Segments[1].EndsWith(";component/"))
{
int index = uri.Segments[1].IndexOf(";");
if (index > 0)
{
string assemblyName = uri.Segments[1].Substring(0, index);

foreach (Assembly asmIter in AppDomain.CurrentDomain.GetAssemblies())
{
if (asmIter.GetName().Name == assemblyName)
{
stream = GetAssemblyResourceStream(asmIter, localPath.Substring(indexLocalPathWithoutAssembly));
break;
}
}
}
}
}

if (stream == null)
{
asm = Assembly.GetCallingAssembly();
stream = GetAssemblyResourceStream(asm, localPath.Substring(indexLocalPathWithoutAssembly));
}
}
}
return stream;
}

// ******************************************************************
/// <summary>
/// The path separator is '/'. The path should not start with '/'.
/// </summary>
/// <param name="asm"></param>
/// <param name="path"></param>
/// <returns></returns>
public static Stream GetAssemblyResourceStream(Assembly asm, string path)
{
// Just to be sure
if (path[0] == '/')
{
path = path.Substring(1);
}

// Just to be sure
if (path.IndexOf('\\') == -1)
{
path = path.Replace('\\', '/');
}

Stream resStream = null;

string resName = asm.GetName().Name + ".g.resources"; // Ref: Thomas Levesque Answer at:
// http://stackoverflow.com/questions/2517407/enumerating-net-assembly-resources-at-runtime

using (var stream = asm.GetManifestResourceStream(resName))
{
using (var resReader = new System.Resources.ResourceReader(stream))
{
string dataType = null;
byte[] data = null;
try
{
resReader.GetResourceData(path.ToLower(), out dataType, out data);
}
catch (Exception ex)
{
DebugPrintResources(resReader);
}

if (data != null)
{
switch (dataType) // COde from
{
// Handle internally serialized string data (ResourceTypeCode members).
case "ResourceTypeCode.String":
BinaryReader reader = new BinaryReader(new MemoryStream(data));
string binData = reader.ReadString();
Console.WriteLine(" Recreated Value: {0}", binData);
break;
case "ResourceTypeCode.Int32":
Console.WriteLine(" Recreated Value: {0}", BitConverter.ToInt32(data, 0));
break;
case "ResourceTypeCode.Boolean":
Console.WriteLine(" Recreated Value: {0}", BitConverter.ToBoolean(data, 0));
break;
// .jpeg image stored as a stream.
case "ResourceTypeCode.Stream":
////const int OFFSET = 4;
////int size = BitConverter.ToInt32(data, 0);
////Bitmap value1 = new Bitmap(new MemoryStream(data, OFFSET, size));
////Console.WriteLine(" Recreated Value: {0}", value1);

const int OFFSET = 4;
resStream = new MemoryStream(data, OFFSET, data.Length - OFFSET);

break;
// Our only other type is DateTimeTZI.
default:
////// No point in deserializing data if the type is unavailable.
////if (dataType.Contains("DateTimeTZI") && loaded)
////{
//// BinaryFormatter binFmt = new BinaryFormatter();
//// object value2 = binFmt.Deserialize(new MemoryStream(data));
//// Console.WriteLine(" Recreated Value: {0}", value2);
////}
////break;
break;
}

// resStream = new MemoryStream(resData);
}
}
}

return resStream;
}

// ******************************************************************
private static void DebugPrintResources(System.Resources.ResourceReader reader)
{
Debug.Print("Begin dump resources: ---------------------");
foreach (DictionaryEntry item in reader)
{
Debug.Print(item.Key.ToString());
}
Debug.Print("End dump resources: ---------------------");
}

// ****************************************************************** // ******************************************************************
}
}

关于c# - 如何从包含其程序集和来自任何程序集的路径的 Uri 加载资源?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32827106/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com