none
Renaming preprocessor directive symbols RRS feed

  • Question

  • Hi,

    I have some code I put together that creates a plugin for Autodesk Revit.

    As there are several versions of Revit, I've used some precompiler directive #if statements to conditionally compile different lines of code depending on the version of Revit, such as this:

    #if DEBUG2018 || RELEASE2018
    
                BitmapImage pb1slideoutImage = new BitmapImage(new Uri("pack://application:,,,/TPBRevitRibbon2018;component/Commands/Standards/StandardsLibrary.png"));
    
    #endif
    
    #if DEBUG2019 || RELEASE2019
    
                BitmapImage pb1slideoutImage = new BitmapImage(new Uri("pack://application:,,,/TPBRevitRibbon2019;component/Commands/Standards/StandardsLibrary.png"));
    
    #endif

    This works well, but now I want to remove one of the versions and replace it with a new version - and so I'd like to rename: DEBUG2018 and RELEASE2018 to DEBUG2020 and RELEASE2020.

    The problem I have is the Visual Studio rename tool won't rename these symbols - "you cannot rename this element"

    If I had to run through my code and rename them manually that would take ages...

    Any ideas how I can rename these?

    Thanks.




    • Edited by archie456 Tuesday, June 18, 2019 4:23 PM
    Tuesday, June 18, 2019 4:19 PM

All replies

  • Ctrl+Shift+H = Replace All

    Select the symbol you want to rename, Ctrl+Shift+H, put in the new value, click replace in all documents.

    Note that personally I would recommend moving away from this approach altogether. If all you're changing is data then there is no reason to recompile your code. In the simplest of cases use a config entry that tells you what "version" to use. In more complex cases introduce per-version types that are dynamically determined at app startup and/or stored in version-specific assemblies such that you can swap out assembly references and not use the compiler directives at all.



    Michael Taylor http://www.michaeltaylorp3.net

    Tuesday, June 18, 2019 5:35 PM
    Moderator
  • Michael - thanks for that, that's exactly what I'm looking for.

    Regarding your point about using a config entry or pre-version types - are there any websites or youtube videos you'd recommend illustrating this approach as I'm fairly new to coding in Visual Studio.

    Cheers.

    Wednesday, June 19, 2019 7:08 AM
  • Here's information on using a config entry.

    https://support.microsoft.com/en-us/help/815786/how-to-store-and-retrieve-custom-information-from-an-application-confi

    https://blog.submain.com/app-config-basics-best-practices/

    In practice, something like this.

    var imageUrl = ConfigurationManager.AppSettings["ImageUrl"];
    
    var pb1slideoutImage = new BitmapImage(new Uri(imageUrl));

    For separate types we're really talking about interfaces.

    https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/

    https://code-maze.com/csharp-interfaces/

    In practice something like this.

    public interface IMyInterface
    {
       BitmapImage GetImage ();
    }
    
    //Assembly for 2018
    public class MyInterface2018
    {
       public BitmapImage GetImage () 
       {
          return new BitmapImage(new Uri(""));
       }
    }
    
    //Assembly for 2020
    public class MyInterface2018
    {
       public BitmapImage GetImage () 
       {
          return new BitmapImage(new Uri(""));
       }
    }
    
    //usage
    void DoSomething ( IMyInterface ifc )
    {
       var pb1slideoutImage = ifc.GetImage();
    }

    The challenge here is programmatically figuring out which version to use. But to make it easier to isolate this you probably want to look into dependency injection such that your code isn't littered with new statements.

    //During app startup - using an example from one of the DIs available 
    void ConfigureContainer ( ContainerBuilder builder )
    {
       if (/* use 2018 */)
          builder.Register<MyInterface2018>().As<IMyInterface>();
       else if (/* use 2020 */)
          builder.Register<MyInterface2020>().As<IMyInterface>();
    }

    Given your sample snippet, if all you need to do is change an image path and everything else remains the same then the config is probably easiest. You could even eliminate the config entry if you could define a folder structure that matches the versioning.

    //Somewhere this gets set to the "version" to use
    var version = 2020;
    
    //Now you can simply use it in the path
    var path = $"pack://...Stuff{version}";

    If there are larger changes than just a path, such as having to compile against newer versions of a third party assembly (e.g. 2018 vs 2020) then you are better off using the container approach as each version-specific assembly can compile against its own third party code. However that also means that you'd need to keep the assemblies in separate paths because you wouldn't want to stomp over the versions. This complicates loading assemblies but isn't too difficult.

    Personally I'd recommend starting with the config file and then move up to custom types if you need to differ more than just an image path.


    Michael Taylor http://www.michaeltaylorp3.net

    Wednesday, June 19, 2019 1:44 PM
    Moderator
  • Hi

    Is your problem solved? If so, please post "Mark as answer" to the appropriate answer, so that it will help other members to find the solution quickly if they face a similar issue.

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, June 25, 2019 8:52 AM
    Moderator