Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. The Lounge
  3. my first source code generator, yea!.. and a question

my first source code generator, yea!.. and a question

Scheduled Pinned Locked Moved The Lounge
csharpwpfquestionwcfcom
10 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    Super Lloyd
    wrote on last edited by
    #1

    Thanks to the newsletter article I finally write my very first own source code generator, yea! :) I found none of the resource on the topic I found were both simple and super helpful, but the cumulative tips in all of them finally unlocked the skill for me! Turns out it's very simple (the main hurdle is that your generator library need to target .Net Standard 2.0).. someone need to write a "source code generator for dummy" article distilled to the essential! ;P (hey, maybe that's an idea hey?) Anyway... I still am left with one.. conundrum? I made a .resx to C# code generator. I know those exists out of the box, but the resulting class doesn't support static binding event if the current culture change, which is annoying with the live culture update support in my application. I have a large chunk of code to enable live culture update, but I thought, wouldn't it be nice if I could have a different C# resource class hey? And now I have! my conundrum is, the default resx class's property looks like that

        internal static string About {
            get {
                return ResourceManager.GetString("About", resourceCulture);
            }
        }
    

    whereas mine looks like that

    	public static string? fsf { get; private set; }
    	public static string? hello { get; private set; }
    	public static string? name { get; private set; }
    
    	static partial void UpdateValues()
    	{
    		var resources = GetDictionaries(Culture);
    		fsf = GetResource("fsf", resources);
    		hello = GetResource("hello", resources);
    		name = GetResource("name", resources);
    	}
    

    so the the default class pay a (negligible) cost on every property access, and my code pay another (negligible but bigger) cost on resource change (but none on property access). and I keep wondering, which one is the best? for context, this class is primarily used through databinding to inform a WPF UI.

    A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

    H Richard DeemingR 2 Replies Last reply
    0
    • S Super Lloyd

      Thanks to the newsletter article I finally write my very first own source code generator, yea! :) I found none of the resource on the topic I found were both simple and super helpful, but the cumulative tips in all of them finally unlocked the skill for me! Turns out it's very simple (the main hurdle is that your generator library need to target .Net Standard 2.0).. someone need to write a "source code generator for dummy" article distilled to the essential! ;P (hey, maybe that's an idea hey?) Anyway... I still am left with one.. conundrum? I made a .resx to C# code generator. I know those exists out of the box, but the resulting class doesn't support static binding event if the current culture change, which is annoying with the live culture update support in my application. I have a large chunk of code to enable live culture update, but I thought, wouldn't it be nice if I could have a different C# resource class hey? And now I have! my conundrum is, the default resx class's property looks like that

          internal static string About {
              get {
                  return ResourceManager.GetString("About", resourceCulture);
              }
          }
      

      whereas mine looks like that

      	public static string? fsf { get; private set; }
      	public static string? hello { get; private set; }
      	public static string? name { get; private set; }
      
      	static partial void UpdateValues()
      	{
      		var resources = GetDictionaries(Culture);
      		fsf = GetResource("fsf", resources);
      		hello = GetResource("hello", resources);
      		name = GetResource("name", resources);
      	}
      

      so the the default class pay a (negligible) cost on every property access, and my code pay another (negligible but bigger) cost on resource change (but none on property access). and I keep wondering, which one is the best? for context, this class is primarily used through databinding to inform a WPF UI.

      A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

      H Offline
      H Offline
      honey the codewitch
      wrote on last edited by
      #2

      I like MS's for the modifiability but assuming yours is generated I guess it doesn't matter so much. Why the nullable string type though? It's already a reference type. If they're all strings I'd ditch making it nullable to keep it simple. Then you can just use a basic null check on it. Unless there's some reason for it I don't get. I wouldn't care about the performance unless you're databinding to a real time graph or something (which I've done) Dictionaries are pretty quick though but the main issue I see with your UpdateValues() routine (given I don't fully understand what it accomplishes) is that if you have a lot of resources it will end up being slow. Have you considered using Lazy<T> and loading on demand on a property by property basis? Lazy<T> Class (System) | Microsoft Docs[^] You can dump one behind each get accessor so it loads the resource the first time on demand. That way you're only loading what you use, and you're not potentially causing a burp in your application's responsiveness when UpdateValues() is called for a lot of resources. But then I'm spitballing, not having seen all of the code.

      Real programmers use butterflies

      S 1 Reply Last reply
      0
      • H honey the codewitch

        I like MS's for the modifiability but assuming yours is generated I guess it doesn't matter so much. Why the nullable string type though? It's already a reference type. If they're all strings I'd ditch making it nullable to keep it simple. Then you can just use a basic null check on it. Unless there's some reason for it I don't get. I wouldn't care about the performance unless you're databinding to a real time graph or something (which I've done) Dictionaries are pretty quick though but the main issue I see with your UpdateValues() routine (given I don't fully understand what it accomplishes) is that if you have a lot of resources it will end up being slow. Have you considered using Lazy<T> and loading on demand on a property by property basis? Lazy<T> Class (System) | Microsoft Docs[^] You can dump one behind each get accessor so it loads the resource the first time on demand. That way you're only loading what you use, and you're not potentially causing a burp in your application's responsiveness when UpdateValues() is called for a lot of resources. But then I'm spitballing, not having seen all of the code.

        Real programmers use butterflies

        S Offline
        S Offline
        Super Lloyd
        wrote on last edited by
        #3

        I decided my option is better.. because it's better to waste (negligible) time on user action (when they change the current culture) instead of while simply viewing data.

        honey the codewitch wrote:

        Why the nullable string type though?

        It's just the new syntactic sugar with nullable reference type (which is just a compiler hint, not a runtime truth). Arguably it's true they wont be null because the default culture dictionary will not be empty (with the way it's constructed). null string never bothered me, so I didn't give it a thought.. but yea.. it might a nice touch.

        honey the codewitch wrote:

        Have you considered using Lazy<T>

        Well this is clearly counter productive, because the whole point of this generator is that the culture might (will?) change. Lazy have fixed value! (I particularly wants live change notification since I opened a software in a unintelligible foreign language and I tried to make it English, turns out I had to find the language menu, select "english" and restart... Thanks google or I would have given up) What you might suggest (and was contemplating) is to have my properties like so instead. Which remove the need for UpdateValues(), this is also more like the MS one is doing it.

        public static string? hello => GetResource("hello", GetDictionaries(Culture));

        A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

        H 1 Reply Last reply
        0
        • S Super Lloyd

          I decided my option is better.. because it's better to waste (negligible) time on user action (when they change the current culture) instead of while simply viewing data.

          honey the codewitch wrote:

          Why the nullable string type though?

          It's just the new syntactic sugar with nullable reference type (which is just a compiler hint, not a runtime truth). Arguably it's true they wont be null because the default culture dictionary will not be empty (with the way it's constructed). null string never bothered me, so I didn't give it a thought.. but yea.. it might a nice touch.

          honey the codewitch wrote:

          Have you considered using Lazy<T>

          Well this is clearly counter productive, because the whole point of this generator is that the culture might (will?) change. Lazy have fixed value! (I particularly wants live change notification since I opened a software in a unintelligible foreign language and I tried to make it English, turns out I had to find the language menu, select "english" and restart... Thanks google or I would have given up) What you might suggest (and was contemplating) is to have my properties like so instead. Which remove the need for UpdateValues(), this is also more like the MS one is doing it.

          public static string? hello => GetResource("hello", GetDictionaries(Culture));

          A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

          H Offline
          H Offline
          honey the codewitch
          wrote on last edited by
          #4

          I didn't realize your culture changed over the life of the application. You could still do this, but you'd just have to reset your lazy init. If Lazy won't let you do it you can make your own poor man's lazy using lock(object) {} but you don't even need to do that unless your object will be accessed from multiple threads. If it's not, you can just do

          if(myres==null) {
          // fetch my res
          }
          return myres;

          and then in your update routine you just set myres to null.

          Real programmers use butterflies

          S 2 Replies Last reply
          0
          • H honey the codewitch

            I didn't realize your culture changed over the life of the application. You could still do this, but you'd just have to reset your lazy init. If Lazy won't let you do it you can make your own poor man's lazy using lock(object) {} but you don't even need to do that unless your object will be accessed from multiple threads. If it's not, you can just do

            if(myres==null) {
            // fetch my res
            }
            return myres;

            and then in your update routine you just set myres to null.

            Real programmers use butterflies

            S Offline
            S Offline
            Super Lloyd
            wrote on last edited by
            #5

            mmm... I guess this is a (negligible) over my (negligible) update, which might save a significant amount of negligible time! mmm.. worth it! :)

            A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

            1 Reply Last reply
            0
            • H honey the codewitch

              I didn't realize your culture changed over the life of the application. You could still do this, but you'd just have to reset your lazy init. If Lazy won't let you do it you can make your own poor man's lazy using lock(object) {} but you don't even need to do that unless your object will be accessed from multiple threads. If it's not, you can just do

              if(myres==null) {
              // fetch my res
              }
              return myres;

              and then in your update routine you just set myres to null.

              Real programmers use butterflies

              S Offline
              S Offline
              Super Lloyd
              wrote on last edited by
              #6

              new generated code thanks to you! :) putting it all, just for fun.... (the other partial file is always the same and jut copied from a generator resource)

              public partial class TestResource
              {
              	public static string fsf 	=> \_fsf ?? (\_fsf = GetResource("fsf", GetDictionaries(Culture)));
              	public static string hello 	=> \_hello ?? (\_hello = GetResource("hello", GetDictionaries(Culture)));
              	public static string name 	=> \_name ?? (\_name = GetResource("name", GetDictionaries(Culture)));
              
              	private static string? \_fsf;
              	private static string? \_hello;
              	private static string? \_name;
              
              	static partial void UpdateValues()
              	{
              		\_fsf = null;
              		\_hello = null;
              		\_name = null;
              	}
              
              	static TestResource()
              	{
              		AddCultureDictionary("", new Dictionary
              		{
              			{ "fsf", "ffs" },
              			{ "hello", "hello" },
              			{ "name", "name" },
              		});
              		AddCultureDictionary("fr-FR", new Dictionary
              		{
              			{ "fsf", "nom de dieu" },
              			{ "hello", "salut" },
              			{ "name", "nom" },
              		});
              	}
              }
              

              A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

              H 1 Reply Last reply
              0
              • S Super Lloyd

                new generated code thanks to you! :) putting it all, just for fun.... (the other partial file is always the same and jut copied from a generator resource)

                public partial class TestResource
                {
                	public static string fsf 	=> \_fsf ?? (\_fsf = GetResource("fsf", GetDictionaries(Culture)));
                	public static string hello 	=> \_hello ?? (\_hello = GetResource("hello", GetDictionaries(Culture)));
                	public static string name 	=> \_name ?? (\_name = GetResource("name", GetDictionaries(Culture)));
                
                	private static string? \_fsf;
                	private static string? \_hello;
                	private static string? \_name;
                
                	static partial void UpdateValues()
                	{
                		\_fsf = null;
                		\_hello = null;
                		\_name = null;
                	}
                
                	static TestResource()
                	{
                		AddCultureDictionary("", new Dictionary
                		{
                			{ "fsf", "ffs" },
                			{ "hello", "hello" },
                			{ "name", "name" },
                		});
                		AddCultureDictionary("fr-FR", new Dictionary
                		{
                			{ "fsf", "nom de dieu" },
                			{ "hello", "salut" },
                			{ "name", "nom" },
                		});
                	}
                }
                

                A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

                H Offline
                H Offline
                honey the codewitch
                wrote on last edited by
                #7

                Sweet. Glad to help. Edit: I was thinking of the case where you do like microsoft and put every error message as a resource. In resource files like that you have hundreds or thousands of resources, and the above code will handle it much better than trying to load them all at once. I figured it was worth it because this is a code generator, so the uses of it are somewhat open ended. IOW some day someone (maybe you) will use it to generate a particularly large resource and you'll be glad it works this way. =)

                Real programmers use butterflies

                S 1 Reply Last reply
                0
                • H honey the codewitch

                  Sweet. Glad to help. Edit: I was thinking of the case where you do like microsoft and put every error message as a resource. In resource files like that you have hundreds or thousands of resources, and the above code will handle it much better than trying to load them all at once. I figured it was worth it because this is a code generator, so the uses of it are somewhat open ended. IOW some day someone (maybe you) will use it to generate a particularly large resource and you'll be glad it works this way. =)

                  Real programmers use butterflies

                  S Offline
                  S Offline
                  Super Lloyd
                  wrote on last edited by
                  #8

                  In fact... your comment scratched a itch.. and I made a new generator that use an underlying ResourceManager (like Microsoft) instead of static dictionaries! yeah! :D Super witch to the rescue! :)

                  A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

                  1 Reply Last reply
                  0
                  • S Super Lloyd

                    Thanks to the newsletter article I finally write my very first own source code generator, yea! :) I found none of the resource on the topic I found were both simple and super helpful, but the cumulative tips in all of them finally unlocked the skill for me! Turns out it's very simple (the main hurdle is that your generator library need to target .Net Standard 2.0).. someone need to write a "source code generator for dummy" article distilled to the essential! ;P (hey, maybe that's an idea hey?) Anyway... I still am left with one.. conundrum? I made a .resx to C# code generator. I know those exists out of the box, but the resulting class doesn't support static binding event if the current culture change, which is annoying with the live culture update support in my application. I have a large chunk of code to enable live culture update, but I thought, wouldn't it be nice if I could have a different C# resource class hey? And now I have! my conundrum is, the default resx class's property looks like that

                        internal static string About {
                            get {
                                return ResourceManager.GetString("About", resourceCulture);
                            }
                        }
                    

                    whereas mine looks like that

                    	public static string? fsf { get; private set; }
                    	public static string? hello { get; private set; }
                    	public static string? name { get; private set; }
                    
                    	static partial void UpdateValues()
                    	{
                    		var resources = GetDictionaries(Culture);
                    		fsf = GetResource("fsf", resources);
                    		hello = GetResource("hello", resources);
                    		name = GetResource("name", resources);
                    	}
                    

                    so the the default class pay a (negligible) cost on every property access, and my code pay another (negligible but bigger) cost on resource change (but none on property access). and I keep wondering, which one is the best? for context, this class is primarily used through databinding to inform a WPF UI.

                    A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

                    Richard DeemingR Offline
                    Richard DeemingR Offline
                    Richard Deeming
                    wrote on last edited by
                    #9

                    How about generating methods for resource strings with placeholders? :) For example, if your resource string Greeting contains "Hello, {0}. The date is {1:D}.", your code could generate something like:

                    private static string _greeting;

                    public static string Greeting(object p0, object p1)
                    {
                    string value = _greeting ??= GetResource("Greeting", GetDictionaries(Culture));
                    return string.Format(value, p0, p1);
                    }


                    "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

                    "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

                    S 1 Reply Last reply
                    0
                    • Richard DeemingR Richard Deeming

                      How about generating methods for resource strings with placeholders? :) For example, if your resource string Greeting contains "Hello, {0}. The date is {1:D}.", your code could generate something like:

                      private static string _greeting;

                      public static string Greeting(object p0, object p1)
                      {
                      string value = _greeting ??= GetResource("Greeting", GetDictionaries(Culture));
                      return string.Format(value, p0, p1);
                      }


                      "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

                      S Offline
                      S Offline
                      Super Lloyd
                      wrote on last edited by
                      #10

                      bah, the class is mostly here for live databinding of resource string in WPF UI. My class fire the static change event supported by bindings! (unlike Microsoft one, obviously)

                      A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

                      1 Reply Last reply
                      0
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • World
                      • Users
                      • Groups