Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ThisAssembly.Resources #45

Closed
kzu opened this issue Feb 2, 2021 · 2 comments · Fixed by #134
Closed

Add ThisAssembly.Resources #45

kzu opened this issue Feb 2, 2021 · 2 comments · Fixed by #134
Labels
enhancement New feature or request

Comments

@kzu
Copy link
Member

kzu commented Feb 2, 2021

Discussed in #34

Originally posted by viceroypenguin January 23, 2021
Proposal: Add another project for exposing string and Stream versions of embedded resources. Accessing the resources is something necessary for most source generators, but also for many other projects; you're accessing embedded resources already in the other ThisAssembly.* projects. It would be nice to be able to have compile-time named access to the embedded resources. Thoughts?

Design

Given the following items in a project:

<PropertyGroup>
   <EmbeddedResourceStringExtensions>$(EmbeddedResourceStringExtensions);.sql</EmbeddedResourceStringExtensions>
</PropertyGroup>

<ItemGroup>
    <EmbeddedResource Include="Foo.txt" />
    <EmbeddedResource Include="MyTemplate.template" Type="Text" />
    <EmbeddedResource Include="Data\Bar.json" />
    <EmbeddedResource Include="..\..\Branding\Icon.png" Link="Branding\Icon.png" Comment="Main app logo" />
    <EmbeddedResource Include="Resources.resx" />
</ItemGroup>

The generator would emit a class like the following:

partial class ThisAssembly
{
  public static partial class Resources
  {
      // <summary>Resources\Foo.txt</summary>
      public static partial class Foo 
      {
        public static string Text => // return cached string version of the resource
        public static byte[] GetBytes() => // read bytes from resource
        public static Stream GetStream() => // get the resource stream
      }

      // <summary>MyTemplate.template</summary>
      public static partial class MyTemplate 
      {
        public static string Text => // return cached string version of the resource
        public static byte[] GetBytes() => // read bytes from resource
        public static Stream GetStream() => // get the resource stream
      }

      // <summary>Resources.resx</summary>
      public static partial class Resources
      {
        public static byte[] GetBytes() => // read bytes from resource
        public static Stream GetStream() => // get the resource stream
      }

      public partial class Branding 
      {
        // <summary>Main app logo</summary>
        // <remarks>Branding\Icon.png</remarks>
        public static partial class Icon
        {
          public static byte[] GetBytes() => // read bytes from resource
          public static Stream GetStream() => // get the resource stream
        }
      }

      public partial class Data 
      {
        // <summary>Data\Bar.json</summary>
        public static partial class Bar 
        {
          public static string Text => // return cached string version of the resource
          public static byte[] GetBytes() => // read bytes from resource
          public static Stream GetStream() => // get the resource stream
        }
    }
  }
}

From the example, note:

  1. All EmbeddedResource items get a static class with both GetBytes and GetStream methods for retrieval
  2. Text files (i.e. .txt and .json) also get a Text property with a cached string read from the resource
  3. Only certain file extensions within EmbeddedResources items are defaulted to Text type (therefore getting a generated Text property). By default, this includes .txt;.json, but can be be extended by appending more extensions to the EmbeddedResourceStringExtensions property.
  4. A single EmbeddedResource can also be annotated with the Type="Text" attribute too, to get the Text property just for that item.
  5. The items' target path (that is, %(RelativeDir)\%(Filename)%(Extension) or %(Link) (for linked files) is used by default as the class <summary /> documentation, unless a Comment="...." is provided in the item, in which case that becomes the <summary /> and the former becomes the <remarks>.
  6. The relative directory of the item is used in the class structure to nest classes and avoid name collisions (this is prevented by the solution structure itself too at that point). This is similar to the nesting done by ThisAssembly.Constants
@kzu kzu added the enhancement New feature or request label Feb 2, 2021
@viceroypenguin
Copy link
Contributor

What if two embedded resources have the same filename? I wonder if a) we should include the path as part of the class structure? and b) if we should optionally include the extension as well?

Otherwise, LGTM!

@kzu
Copy link
Member Author

kzu commented Feb 2, 2021

Ha, good catch. Yeah, making the path part of the class structure makes sense. Like ThisAssembly.Resources.Branding.Icon. It's perfect :), edited!

@kzu kzu closed this as completed in #134 Nov 30, 2022
kzu pushed a commit that referenced this issue Nov 30, 2022
@devlooped devlooped locked and limited conversation to collaborators Sep 2, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants