dotnet / interactive-window

Visual Studio Interactive Window
MIT License
64 stars 35 forks source link

Specify location of DLLs for C# Interactive #116

Open brettrowberry opened 6 years ago

brettrowberry commented 6 years ago

F# Interactive #help shows these options:

#r "file.dll";;        Reference (dynamically load) the given DLL
#I "path";;            Add the given search path for referenced DLLs
#load "file.fs" ...;;  Load the given file(s) as if compiled and referenced
#time ["on"|"off"];;   Toggle timing on/off
#help;;                Display help
#quit;;                Exit

F# Interactive command line options:

See 'fsi --help' for options

C# Interactive #help shows these options:

Keyboard shortcuts:
  Enter         If the current submission appears to be complete, evaluate it.  Otherwise, insert a new line.
  Escape        Clear the current submission.
  UpArrow       Replace the current submission with a previous submission.
  DownArrow     Replace the current submission with a subsequent submission (after having previously navigated backwards).
  Ctrl-C        Exit the REPL.
REPL commands:
  #help         Display help on available commands and key bindings.
Script directives:
  #r            Add a metadata reference to specified assembly and all its dependencies, e.g. #r "myLib.dll".
  #load         Load specified script file and execute it, e.g. #load "myScript.csx".

One of the great features of F# scripts is the #I directive, which tells F# Interactive where to look for referenced DLLs.

Is there an equivalent way to do this in C# scripts?

lcorrigan commented 5 years ago

I've just started exploring C# Interactive and evaluating F# alongside. I would have really liked this in the C# Interactive too, to give me the equivalent of "sys.path.append()" I use in python all the time.

tmat commented 5 years ago

There is:

ReferencePaths.Add(@"c:\dlls");

The new paths are used to resolve relative #r directives starting with the next submission.

SourcePaths.Add(@"c:\scripts");

The new paths are used to resolve relative #load directives starting with the next submission.

brettrowberry commented 5 years ago

Is this documented anywhere?

lcorrigan commented 5 years ago

I only see it in the unit tests for the Interactive window source code. Using the ReferencePaths.Add or the SourcePaths.Add commands are a bit of a chicken before the egg scenario when it comes to script files though.. You have to have any "#r" or "#load" commands at the beginning of any file, but you need to run ReferencePaths.Add or SourcePaths.Add before that to tell an IDE (intellisense etc) how to resolve those '#r' calls. We have a folder of .NET dll's that are external to our script code directory tree. I did not want to use absolute paths on each '#r' line in the scripts and I was trying to avoid having too much dependency on any specific IDE's project settings to resolve them. I tried splitting the pointing and the loading into two different files and didn't have any luck with Intellisense in visual studio. Although the commands mentioned above are fine for telling the interactive session where to look, it doesn't replace F#'s '#I' command for pointing an IDE in the right place. With F# (which is looking really promising for my overall needs and method of operating.....) I was able to get Intellisense in VS2019 without any project references, or project path settings or anything other than a single line of "#I" pointing to my external libs. Never thought my python + net replacement evaluation would come down to a single '#I' line showdown.

tmat commented 5 years ago

@lcorrigan Correct, the ReferencePaths and SourcePaths are most useful in Interactive Window. The former can also be specified on command line of csi: csi /lib:C:\dlls.

Indeed, #I directive would allow the IDE to know where to look without external configuration, although it also makes the script tied to absolute paths on the machine. So you can't just copy and run the script on another machine unless it has the same directory structure.

You could potentially work around the lack of #I by creating a hard link to the DLL directory in the directory containing the script.

tmat commented 5 years ago

@lcorrigan

We have a folder of .NET dll's that are external to our script code directory tree.

I'm curious about this setup. Can you share more details?

lcorrigan commented 5 years ago

@tmat We have been using IronPython with a folder of .NET libraries written in VB.NET for a number of years now. Some are 32-bit ".NET Framework" and will have to stay that way for reason's I'd rather not waste your time on. I've been evaluating replacement options for IronPython. Long story short, we have structured different directories of python code to simply reference the single bucket of libraries, and since it was interpreted, no DLL's were ever auto-copied from that location to the bin folder. Just one SVN checkout on the CPU - no mess. When using the editor (VS or Eclipse Pydev), we just needed to add the lib path to the project. For the interpreter window, there was a config file we placed the path in to find it at startup (similar to /lib: for CSharpInteractive.rsp). For auto-work, we used Jenkins jobs that would run python modules (which would do sys.path.append("the single lib folder")) and had the best of all 3 worlds, never needing to muck with packaging. There might be things we could explore to make the transition to C# Scripting easier (like create a Nuget for our libs? etc) or re-structuring how we do things, but for now I was just trying to find the smoothest transition to a language that fit our dev model the best.

Where I'm at now: I can get the Interactive window to see the external lib folder (thanks to your commands and/or the CSharpInteractive.rsp file), and running on the command line accepts external paths for references, so I'm covered there too. However, the minute I removed my using absolute path #r calls in my csx files, the VS editor lost sight of the libraries. I know (or believe) the Rosyln compiler only support full paths, but I figured if I gave the project enough information (references/paths etc) it would be able to figure it out. Nope. I've not found the magic combination of project settings to make it resolve /intellisense without each .dll's absolute path.

I've been struggling with this concept on-and-off since 2003 (original pythonnet + Spyder etc), so I'm used to this, but what's astonishing me the most is how little I've had to tell F# in order for it to just work for my use-case. I think that '#I' flag is providing the missing link I'd need on C#. Unfortunately for my relationship with my team, the more I'm playing with F#, the more I'm starting to like what I see for the kind of work I do - a lot actually.....might be time to go rogue.

brettrowberry commented 5 years ago

@lcorrigan welcome to the Dark Side :-)