I have the following code which will check if a List<int> is compatible with type IEnumerable<object>. Covariance does not apply to value types, so this expression should evaluate to false.
public class WatchWindowTests
{
[Fact]
public void WhenRun_WillEvalueToFalseInCode_AndTrueInWatchWindow()
{
object listOfInts = new List<int>();
var x = false;
// This line evaluates to false - covariance does not apply to value types
if(listOfInts is IEnumerable<object>)
{
// This line is never executed
x = true;
}
Assert.False(x);
}
}
In the code above, the code will not enter the if block, as expected. However, in the watch window, the same expression will evaluate to true. (See image.)
Is there a reason for this, or is there a bug in Visual Studio? (I'm using Visual Studio 2022 17.0.4)
Related
So basically I only want to display the Command when I right click on a file named "example.cs". Since I am using Visual Studio 2019 I can't go with the old BeforeQueryStatus way. Instead using the ProvideUIContextRule Attribute on my Package class. Which currently looks something like this:
[ProvideUIContextRule(_uiContextSupportedFiles,
name: "Supported Files",
expression: "CSharp",
termNames: new[] { "CSharp" },
termValues: new[] { "HierSingleSelectionName:.cs$" })]
Which totally looks fine for the extension of the file itself. So is there any way to restrict it to example.cs?
By the way I am using this Guide.
So for everyone else having the same issue as I had. The solution is fairly simple, regarding to the MSDN:
(...) The term evaluates to true whenever the current selection in the active hierarchy has a name that matches the regular expression pattern(...)
So basically changing
{ "HierSingleSelectionName:.cs$" } to { "HierSingleSelectionName:Program.cs$" } will only show files that end with Program.cs.
This leads to, that everything after the semicolon contains a Regular Expression.
To determine your command's visibility, you can implement QueryStatus method.
Implement Microsoft.VisualStudio.OLE.Interop.IOleCommandTarget like CommandsFilter. And add it as service to package.
var serviceContainer = (IServiceContainer)this; // this - is your Package/AsyncPakage
var commandTargetType = typeof(IOleCommandTarget);
var commandsFilter = new CommandsFilter();
serviceContainer.RemoveService(commandTargetType);
serviceContainer.AddService(commandTargetType, commandsFilter);
On every commands update will be called method QueryStatus in CommandsFilter.
Wait for your command id and change it status
class CommandsFilter : IOleCommandTarget {
// ...
public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) {
var cmdId = prgCmds[0].cmdID;
// check cmdId and set status depends on your conditions
// like fileName == "example.cs"
prgCmds[0].cmdf = (uint)GetVsStatus(status);
//....
}
private OLECMDF GetVsStatus(CommandStatus commandStatus) {
OLECMDF ret = 0;
if (commandStatus.HasFlag(CommandStatus.Supported))
ret |= OLECMDF.OLECMDF_SUPPORTED;
if (commandStatus.HasFlag(CommandStatus.Enabled))
ret |= OLECMDF.OLECMDF_ENABLED;
if (commandStatus.HasFlag(CommandStatus.Invisible))
ret |= OLECMDF.OLECMDF_INVISIBLE;
return ret;
}
Check sample with QueryStatus and others MS samples
I'm developing a Visual Studio extension in which one of the implemented commands needs to be available only when the active document is a text document (like e.g. the Visual Studio's "Toggle Bookmark" does). The problem is that I can't figure out how to tell when that's the case.
Right now I have a half working solution. In the package's Initialize method I subscribe to DTE's WindowActivated event, and then whenever a window is activated I check if the window DocumentData property is of type TextDocument:
protected override void Initialize()
{
base.Initialize();
var dte = Package.GetGlobalService(typeof(EnvDTE.DTE)) as EnvDTE.DTE;
dte.Events.WindowEvents.WindowActivated += WindowEventsOnWindowActivated;
//More initialization here...
}
//This is checked from command's BeforeQueryStatus
public bool ActiveDocumentIsText { get; private set; } = false;
private void WindowEventsOnWindowActivated(Window gotFocus, Window lostFocus)
{
if (gotFocus.Kind != "Document")
return; //It's not a document (e.g. it's a tool window)
TextDocument textDoc = gotFocus.DocumentData as TextDocument;
ActiveDocumentIsText = textDoc != null;
}
The problem with this approach is that 1) Window.DocumentData is documented as ".NET Framework internal use only", and 2) this gives a false positive when a document that has both a code view and a design view (e.g. a .visxmanifest file) is open in design mode.
I have tried to use IVsTextManager.GetActiveView as well, but this is returning the last active text view opened - so if I open a .txt file and then a .png file, it returns data for the .txt file even if it's not the active document anymore.
So, how do I check if the active document is a text document, or the code view of a document that can have a designer... and if possible, not using "undocumented" classes/members?
UPDATE: I found a slightly better solution. Inside the window activated handler:
ActiveDocumentIsText = gotFocus.Document.Object("TextDocument") != null;
At least this one is properly documented, but I still have the problem of false positives with designers.
I finally got it. It's somewhat tricky, but it works and is 100% "legal". Here's the recipe:
1- Make the package class implement IVsRunningDocTableEvents. Make all the methods just return VSConstants.S_OK;
2- Add the following field and the following auxiliary method to the package class:
private IVsRunningDocumentTable runningDocumentTable;
private bool DocIsOpenInLogicalView(string path, Guid logicalView, out IVsWindowFrame windowFrame)
{
return VsShellUtilities.IsDocumentOpen(
this,
path,
VSConstants.LOGVIEWID_TextView,
out var dummyHierarchy2, out var dummyItemId2,
out windowFrame);
}
3- Add the following to the Initialize method of the package class:
runningDocumentTable = GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable;
runningDocumentTable.AdviseRunningDocTableEvents(this, out var dummyCookie);
4- Don't blink, here comes the magic! Implement the IVsRunningDocTableEvents.OnBeforeDocumentWindowShow method as follows:
public int OnBeforeDocumentWindowShow(uint docCookie, int fFirstShow, IVsWindowFrame pFrame)
{
runningDocumentTable.GetDocumentInfo(docCookie,
out var dummyFlags, out var dummyReadLocks, out var dummyEditLocks,
out string path,
out var dummyHierarchy, out var dummyItemId, out var dummyData);
IVsWindowFrame windowFrameForTextView;
var docIsOpenInTextView =
DocIsOpenInLogicalView(path, VSConstants.LOGVIEWID_Code, out windowFrameForTextView) ||
DocIsOpenInLogicalView(path, VSConstants.LOGVIEWID_TextView, out windowFrameForTextView);
//Is the document open in the code/text view,
//AND the window for that view is the one that has been just activated?
ActiveDocumentIsText = docIsOpenInTextView && pFrame == logicalViewWindowFrame;
return VSConstants.S_OK;
}
I want automatic deduction of the arguments of a templated function which accepts a function, while using lambdas. This Example shows some of my options:
template <class T>
void foo(void (*func)(T)) {
T val;
// do something with val and func...
}
int main() {
auto pfunc0 = [] (int) { /*...*/ };
void (*pfunc1)(int) = [] (int) { /*...*/ };
auto* pfunc2 = +[] (int) { /*...*/ };
foo(pfunc0); // not ok
foo<int>(pfunc0); // ok, but redundant
foo(pfunc1); // ok, but redundant
foo(pfunc2); // ok
}
pfunc2 uses a trick I learned here: Obtaining function pointer to lambda?. So actually I should be happy with the pfunc2 case as it is concise and non repeating code, unfortunately the Visual C++ 2012 IDE complains it was erroneous code even though it compiles just fine.
Are there any workarounds or recommendations for this problem?
IDE error messages:
In the "auto* pfunc2" line: The IDE underlines 'auto' and says
Error: cannot deduce 'auto' type
also it underlines '[' where it complains
Error: more than one conversion function from "lambda[]void (int)->void" to a build-in type applies:
function "lambda[]void (int)->void::operator void (*)(int)() const"
function "lambda[]void (int)->void::operator void (*)(int)() const"
function "lambda[]void (int)->void::operator void (*)(int)() const"
This is related to this bug (closed as "by design"). VC++ supports several calling conventions on x86 and lambdas with empty capture lists provide conversions to them all. That's why there's ambiguity.
Unfortunately, there's no workaround listed that you haven't already tried.
By the way, this bug is listed as fixed in Visual C++ 2015 Update 2
When debugging in IDE, how does the IDE know how to calculate the watch value without changing the environment (writing to file, writing result to DB)?
Your observation cannot be generalized. An IDE typically makes changes during debugging, especially if a property has a side effect.
Visual Studio
The following C# code:
using System;
namespace EvaluateChangesValue
{
class Program
{
static void Main()
{
var program = new Program();
Console.WriteLine(program.Value);
Console.ReadLine();
Console.WriteLine(program.Value);
Console.ReadLine();
}
private int member;
private int Value => member++;
}
}
Set a breakpoint at the first ReadLine(), then add program.Value to the watch window and see how the value gets increased due to the member++ statement.
Eclipse
In Java and Eclipse, it's a bit harder to make the same proof because for these reasons:
In Java it's more clear whether you call a method or access a field.
You need the "Expressions" window, which is not available by default
Re-evaluation needs user interaction
The code is similar to C#:
public class Program {
public static void main(String[] args)
{
Program p = new Program();
System.out.println(p.member);
System.console().readLine();
System.out.println(p.member);
System.console().readLine();
}
private int member;
public int getMember()
{
return member++;
}
}
And the screenshot:
I've created a significant number of methods to help me perform unit test assertions in Visual Studio 2010. I've also enabled "Double-click a Failed or Inconclusive unit test result displays the point of failure in the test" option in the Test Execution options. My issue is that with these helper methods, I'd like the point of failure to be the stack frame calling my helper method, not the exception being thrown within the helper method.
Obviously, I can do "ShowDetails" and click higher in the stack, but that will pretty much cancel out any time saved by using the helper method.
I've tried using the various [Debugger*] attributes on my method without success.
Here's some example code to illustrate my issue.
public void MyTest()
{
// ACT
var res = DoSomething();
// ASSERT
AssertDateRange(res, TimeSpan.FromDays(7));
}
public static void AssertDateRange(DateTime value, TimeSpan range)
{
var difference = DateTime.Now.Subtract(value);
if (Math.Abs(range.TotalMilliseconds) - Math.Abs(difference.TotalMilliseconds) < 0)
{
throw new AssertFailedException("DateTime was not within the expected range from now.");
}
}
I'd like for the double-click to place me on the method call within the MyTest method, while it now places me on the throw within the AssertDateRange method.