I've got a method that tries to Add n files to a repository, using SharpSVN. Any number of these files can throw an error, which I catch, and then move on to the next file and try to add that, and so on. I want to alert the user X times, where X is the number of different reasons. So if I added 5 files and 3 failed for one reason and 2 failed for a different reason, I want to present 2 errors. If they all fail for the same reason, 1 error. Five different reasons? Present 5 errors.
I made a class, FileException, that has two properties (Exception Ex, string FileName) and tried to implement a collection so I could group it on the Exception.
public void AddFiles(List<string> files)
{
var sb = new StringBuilder();
var args = new SvnAddArgs {Depth = SvnDepth.Children};
var exes = new Collection<FileException>();
foreach (var file in files)
{
try
{
//only here for testing purposes described below
if (file.Contains("png"))
throw new AccessViolationException();
SVNClient.Add(file, args);
}
catch (Exception ex)
{
exes.Add(new FileException(ex, file));
}
}
if (exes.Count > 1)
{
exes.GroupBy(s => s.Ex.GetType());
Unique<Log>.Instance.AddExceptions(exes);
}
else if (exes.Count == 1)
Unique<Log>.Instance.AddException(exes[0].Ex);
}
public void AddExceptions(Collection<FileException> e)
{
var sb = new StringBuilder();
var ex = e[0].Ex;
for(var i=0; i < e.Count;i++)
{
Logs.Add(new LogMessage(e[i].Ex));
sb.AppendLine(e[i].FileName);
WriteLogFile(new LogMessage(e[i].FileName, e[i].Ex));
if (ex.GetType() == e[i].Ex.GetType())
continue;
ShowLogError(new LogMessage(sb.ToString(), ex));
sb.Length = 0;
ex = e[i].Ex;
}
//Call ShowLogError if only 1 type of Exception in all of e
if (!string.IsNullOrEmpty(sb.ToString()))
ShowLogError(new LogMessage(sb.ToString(), ex));
}
public void ShowLogError(ILogMessage log)
{
//Extra formatting left out as its irrelevant to code sample
XtraMessageBox.Show(log.message, log.title);
}
So, what AddException is trying to do is store the first exception in ex in a sort of flag, and then iterate over its parameter and message the user when the current item is different than the flag item.
Test Case:
Add 3 files (fileA.cs, fileB.png, fileC.cs)
Expected Results:
ShowLogError() shows me fileA and fileC, since these threw the same error
ShowLogError() shows me fileB, which threw the hard-coded exception since it contains "png"
Actual Results:
ShowLogError() shows fileA and B, which threw 2 different exceptions
ShowLogError() shows fileC, which threw the same as fileA.
So I think there's a problem with how I'm using GroupBy() in the AddFiles method, but I'm totally clueless here. Oh, also, I get this note from Resharper on my GroupBy() statement: Return value of pure method is not used but I'm not really sure what is meant by "pure method".
Edit: I just tried using OrderBy instead of GroupBy, but I get the same results for the aforementioned test case.
Edit 2: Using my OrderBy instead of GroupBy, here is a screenshot from my Immediate Window:
![enter image description here][1]
Added highlighting just to make it easier to differentiate the three rows.
Should items 0 and 2 be together since their Ex is of the same type?
Edit Adding a screenshot of Gert Arnold's answer to show that it does not compile. I proposed an edit that does compile and it was removed. I appreciate his help, of course, but it wasn't 100% working.
When you've got your exes collection, basically all you have to do is:
var result = fileExceptions.GroupBy(e => e.Ex.GetType().Name)
.Select(g => new
{
g.Key, Files = string.Join("\r\n", g.Select(x => x.FileName).ToArray())
});
I believe that you are not capturing the results of of your "GroupBy" or "OrderBy" clauses.
What about this:
List<Type> types = exes.Select(x => x.GetType()).Distinct().ToList();
This gives you the unique types of FileExceptions that were added to the collection
Related
im trying to deploy a simple search function that uses a simple tag system, probably there are better ways to bt this is the solution i landed on:
public async Task<ActionResult<IEnumerable<t_usuarios_pub>>> Gett_usuarios_pubByTag(string tag)
{
string[] TagList;
TagList = tag.Split(',');
List<t_usuarios_pub> results = new List<t_usuarios_pub>();
var pubs = from m in _context.t_usuarios_pub select m;
if (!String.IsNullOrEmpty(tag))
{
foreach (var Itag in TagList)
{
pubs = pubs.Where(s => (s.tag.Contains(Itag) && s.estatus<2)).OrderBy(x => x.estatus);
foreach(var x in pubs)
{
if (!results.Contains(x))
{
results.Add(x);
}
}
}
}
return await results.AsQueryable().ToListAsync();
}
problem is that the List results cant be converted to IQueryable, this is the error stack.
Any idea of how i can properly implement it ?
System.InvalidOperationException:
The source 'IQueryable' doesn't implement 'IAsyncEnumerable<UserPostAPI.Models.t_usuarios_pub>'.
Only sources that implement 'IAsyncEnumerable' can be used for Entity Framework asynchronous operations.
ยดยดยด
Since results is a local variable of List<> type, I don't believe you need to await the last line. It might just work with:
return results.AsQueryable();
In which case, your method may not even need to be an async method. Or, depending on what _context is, perhaps the await needs to be on the pubs filter call:
pubs = await pubs.Where(s => (s.tag.Contains(Itag) && s.estatus<2))
.OrderBy(x => x.estatus)
.ToListAsync();
Furthermore, since your method says it returns an IEnumerable<>, you probably don't need the .AsQueryable(), either:
return result;
There's also a lot of refactoring you could do -- here are just a few things you may want to consider:
Move the String.IsNullOrEmpty(tag) check to the beginning of the method as a guard.
If this is user input, trim the split tags in TagList to avoid any issues with extra whitespace, and then be sure to remove any resulting empty members.
You could put the estatus < 2 check in your query to reduce having to re-check it again for every item in pubs for every ITag.
Some people decided to close my previous question, but the question they linked (What is a NullReferenceException, and how do I fix it?) did not have an answer. This question is fundamentally different since the enumerable is populated. It is not null. Just as the first answer stated, I placed "strategic breakpoints" and checked the variables.
I'm debugging a XUnit test and it turns out that in my business logic the iteration variable in the foreach loop is throws an exception "Object Reference not set to instance of object". However, the list over which the iteration is happening is NOT null. I can see that when I'm debugging. Here is the code:
Business logic:
List<string> regionArray = new List<string>();
if (someCondition)
{
regionArray = _utils.GetRegions(someParam); // this is not returning null
}
foreach (var region in regionArray)
{
var query = from dataSet in myDataSets
where dataSet.Location == region
select dataSet;
var queryResult = query.FirstOrDefault();
if (queryResult == null)
{
// do stuff
} else if (queryResult.State != States.Provisioned)
{
// do stuff
}
}
Here is how I am mocking the _utils.GetRegions call, but I dont think thats the problem.
private Mock<IUtils> _mockRegionUtils;
[Fact]
public void ItWorks()
{
// do stuff
_mockRegionUtils = new Mock<IUtils>();
_mockRegionUtils.Setup(utils => utils.GetRegions(It.IsAny<ISomeParam>())).Returns(new List<string>() {"america", "china"});
// call business logic
}
I have checked all the types in the debugger. regionArray.GetType() returns {System.Collections.Generic.List`1[System.String]}. when I type region into the console however, i get:
region
'region' threw an exception of type 'System.NullReferenceException'
how is this possible?
EDIT: fixed a typo above, sorry about that. Something weird though, so if I reassign the value of regionArray to be an inline list, it still fails. But if I define a new inline list and iterate over that, the looping works fine.
List<string> regionArray = new List<string>();
if (someCondition)
{
regionArray = _utils.GetRegions(someParam); // this is not returning null
}
regionArray = new List<string>() {"china", "america"};
List<string> temp = new List<string>() {"foo", "bar"}
foreach (var region in regionArray)
{
// region still throws null reference exception
foreach (var tempVar in temp)
{
var c = tempVar; // this works. tempvar is never null.
}
var query = from dataSet in myDataSets
where dataSet.Location == region
select dataSet;
var queryResult = query.FirstOrDefault();
if (queryResult == null)
{
// do stuff
} else if (queryResult.State != States.Provisioned)
{
// do stuff
}
}
EDIT 2: So I tried iterating over the regionArray in the same way just before the logic above, and it worked fine.
List<string> regionArray = new List<string>();
if (someCondition)
{
regionArray = _utils.GetRegions(someParam); // this is not returning null
}
foreach (var region in regionArray)
{
var c = region; // this works
}
foreach (var region in regionArray)
{
// region throws null reference exception
var query = from dataSet in myDataSets
where dataSet.Location == region
select dataSet;
var queryResult = query.FirstOrDefault();
if (queryResult == null)
{
// do stuff
} else if (queryResult.State != States.Provisioned)
{
// do stuff
}
}
so most likely, it is not a problem with the moq object. based on #Iliar's suggestion, I will see if regionArray gets modified, but at first glance since regionArray is not used within the loop, my answer would be "no".
Update: I got around this issue by renaming the region looping variable to a different name. As it turns out, I was doing another foreach (var region ...) loop earlier in my code. I spoke to some senior colleagues as to why these 2 names would conflict with each other, and they said maybe it was some issue with symbols in VSCode and not really with my actual code. Thank you all for your help!
There was a lot of info in this thread, so just to summarize here are a few bulletpoints in case it is helpful to someone else in the future:
When debugging an XUnit test, I was seeing my looping variable in my foreach displaying the following info in the tooltip 'region' threw an exception of type 'System.NullReferenceException' Data [IDictionary]:{System.Collections.ListDictionaryInternal} HResult [int]:-2147467261 HelpLink [string]:null InnerException [Exception]:null Message [string]:"Object reference not set to an instance of an object." Source [string]:"9dd66c33104045bba27ad3fc9fb95185" StackTrace [string]:" at <>x.<>m0(<IngestEvents>d__13 <>4__this)" TargetSite [MethodBase]:{System.String <>m0(<IngestEvents>d__13)} Static members ....
even as I stepped INTO the loop, the tooltip for region was still showing the above, and when I typed region into the console, I got 'region' threw an exception of type 'System.NullReferenceException'.
The above 2 points led me to believe region was null. However, through #IVSoftware 's help, I verified that region was not actually null, because the assertion was passing.
I then looked at the rest of my code, and as a random guess, I tried renaming the looping variable region to something else. When I did, region was correctly set to the elements of the list.
Hi I really hope to be helpful. First I will answer your question "how is this possible?" and I think I can explain why your edited question with the inline list works. True, the GetRegions method returns a list that is not null. Sure, if you call GetType() on this it correctly identifies it as a "list of strings". I believe however, that the GetRegions method is returning a list that contains at least one null value. And you prove it out yourself when you added the edit, because you say this works:
regionArray = new List<string>() {"china", "america"};
But try making a list with three values like this where one of them is null and probably the loop will fail again.
regionArray = new List<string>() {"china", null, "america"};
This suggests a bug inside the GetRegions method is putting a null value into the list that it is returning. Adding these two lines at the beginning of your loop might go a long way to identifying the issue:
foreach (var region in regionArray)
{
// Look for this in the Visual Studio 'Output' window
System.Diagnostics.Debug.WriteLine(region == null ? "Null" : region);
// You believe that region is not null. So 'assert' that
// this evaluates to True and if it doesn't the debugger will break here.
System.Diagnostics.Debug.Assert(region != null, "Break on this line if region is null");
...
From what I can tell, I would look inside your GetRegions(someParam) method and see if it's inserting a null into the list somewhere. Good luck!
List<string> regionArray = new List<string>();
if (someCondition)
{
regionArray = _utils.GetRegions(someParam); // this is not returning null
}
this will override the regionArray instance, to the GetRegions instance, so creating new List<string> instance is useless.
What you want is :
List<string> regionArray = new List<string>();
if (someCondition)
{
regionArray.AddRange(_utils.GetRegions(someParam));
}
which is using this new instance, and add the resulted elements inside it.
If _utils.GetRegions(someParam) returns empty set, then regionArray will not be null, but it'll be empty regionArray.Count == 0.
this is also can be done using ToList as well:
var regionArray = _utils.GetRegions(someParam).ToList();
now , you need to check regionArray after that :
if(regionArray.Count == 0)
{
// do something
}
Or using Linq
if(!regionArray.Any())
{
// do something
}
if the collection is not empty then you can iterate through the list and validate each string inside this list before you process it:
foreach (var region in regionArray)
{
// check if the element is null or empty
// if true, will skip this element and go to the next one
if(string.IsNullOrEmpty(region)) { continue; } // go to the next iteration
// get the results
var queryResult = myDataSets.FirstOrDefault(x=> x.Location == region);
if (queryResult == null)
{
// do stuff
}
else if (queryResult.State != States.Provisioned)
{
// do stuff
}
}
I'm using selenium to automate some data entry tasks for work.
Problem I'm having:
I need to check if a select (dropdown) has an option, and if so select it, otherwise continue.
The select has around 200 options which I didn't think was a lot but it seems to take a long time to go through the list and I'm wondering how I can speed it up.
I'm assuming its related to the type of objects the list is comprised of being beefy? (list of IWebElement)
Tried a basic for loop, as well as using the .Any method on the list, both seem equally unusually slow.
SelectElement brokeragePayeeOfficeSelect = new SelectElement(webDriver.FindElement(By.Id("ContentPlaceHolder1_ddBrokeragePayee")));
IList<IWebElement> officeOptions = brokeragePayeeOfficeSelect.Options;
bool result = officeOptions.Any(o => o.Text == brokerageOfficeArray[i]);
if (result)
{
brokeragePayeeOfficeSelect.SelectByText(brokerageOfficeArray[i]);
}
else
{
Console.WriteLine("Missing:" + brokerageOfficeArray[i]);
continue;
}
The other option is to make the SelectElement.SelectByText method throw its exception faster. Not sure how to do that. Usually takes a minute or so for it to throw.
Ideas?
Your iteration with Any to check if the option is present is rather expensive. Instead try to select the option and catch the exception:
var brokeragePayeeOfficeSelect = new SelectElement(webDriver.FindElement(By.Id("ContentPlaceHolder1_ddBrokeragePayee")));
try {
brokeragePayeeOfficeSelect.SelectByText(brokerageOfficeArray[i]);
} catch (NoSuchElementException) {
Console.WriteLine("Missing:" + brokerageOfficeArray[i]);
continue;
}
I have a program that sets "Mark" parameter values, unique for each "identical" beam or column. This usually results in more than one beam with the same "Mark" parameter, and Revit displays the odd "Warning - can be ignored.......Elements have duplicate 'Mark' values" (odd because it cannot really be ignored, because it always displays).
Does anyone know how to turn off this warning during the execution of a program? I will likely be collecting additional element types (such as connections, stiffeners, or even foundations) and assigning "Mark" parameters, and it would be nice to avoid having that warning appear 4 or 5 times.
It's actually pretty straight forward. You can use something called IFailurePreprocessor to catch all of these warnings and dismiss them from code:
Create a preprocessor class:
public class DuplicateMarkSwallower : IFailuresPreprocessor
{
public FailureProcessingResult PreprocessFailures(FailuresAccessor a)
{
var failures = a.GetFailureMessages();
foreach (var f in failures)
{
var id = f.GetFailureDefinitionId();
if (BuiltInFailures.GeneralFailures.DuplicateValue == id)
{
a.DeleteWarning(f);
}
}
return FailureProcessingResult.Continue;
}
}
Then you can use it like so:
using (var trans = new Transaction(_doc, "Creating Numbers"))
{
trans.Start();
// Set failure handler
var failureOptions = trans.GetFailureHandlingOptions();
failureOptions.SetFailuresPreprocessor(new DuplicateMarkSwallower());
trans.SetFailureHandlingOptions(failureOptions);
// do your thing here
trans.Commit();
}
I can get a list from the solution of all calls to a particuliar method using the following code:
var createCommandList = new List<MethodSymbol>();
INamedTypeSymbol interfaceSymbol =
(from p
in solution.Projects
select p.GetCompilation().GetTypeByMetadataName(
"BuySeasons.BsiServices.DataResource.IBsiDataConnection")
).FirstOrDefault();
foreach (ISymbol symbol in interfaceSymbol.GetMembers("CreateCommand"))
{
if (symbol.Kind == CommonSymbolKind.Method
&& symbol is MethodSymbol)
{
createCommandList.Add(symbol as MethodSymbol);
}
}
foreach (MethodSymbol methodSymbol in createCommandList)
{
foreach (ReferencedSymbol referenceSymbol
in methodSymbol.FindReferences(solution))
{
foreach (ReferenceLocation referenceLocation
in from l
in referenceSymbol.Locations
orderby l.Document.FilePath
select l)
{
if (referenceLocation.Location.GetLineSpan(false)
.StartLinePosition.Line ==
referenceLocation.Location.GetLineSpan(false)
.EndLinePosition.Line)
{
Debug.WriteLine("{0} {1} at {2} {3}/{4} - {5}",
methodSymbol.Name,
"(" + String.Join(",",
(from p
in methodSymbol.Parameters
select p.Type.Name + " " + p.Name).ToArray()
) + ")",
Path.GetFileName(referenceLocation.Location.GetLineSpan(false)
.Path),
referenceLocation.Location.GetLineSpan(false)
.StartLinePosition.Line,
referenceLocation.Location.GetLineSpan(false)
.StartLinePosition.Character,
referenceLocation.Location.GetLineSpan(false)
.EndLinePosition.Character));
}
else
{
throw new ApplicationException("Call spans multiple lines");
}
}
}
}
But this gives me a list of ReferencedSymbol. Although this gives me the file and line number that the method is called from I would also like to get the specific arguments that the method is called with. How can I either convert what I have or get the same information with Roslyn? (notice the I first load the solution with the Solution.Load method and then loop through to find out where the method is defined/declared (createCommandList)).
You are already using Roslyn here. When you have a referenceSymbol, you can get at the Method Declaration Syntax and then look down into the tree to get the Parameter list.
I've inserted a arguments variable that uses your referenceSymbol:
// Snip start
foreach (MethodSymbol methodSymbol in createCommandList)
{
foreach (ReferencedSymbol referenceSymbol
in methodSymbol.FindReferences(solution))
{
var arguments = referenceSymbol.Definition.DeclaringSyntaxNodes.First()
.DescendantNodes().OfType<ParameterSyntax>().ToList();
foreach (ReferenceLocation referenceLocation in
from l
in referenceSymbol.Locations
orderby l.Document.FilePath
select l)
{
// Snip end
When you perform a Debug output, you can then use that list of arguments to get the names.
My solution requires getting the First() of the DeclaringSyntaxNodes, which I don't like very much but cannot find another way to get at the Descendant Nodes of the Syntax Tree.
I have discovered another way of getting the Parameter list from a method that might work for others as well.
Say I have the following method that has two parameters:
public string DebugPage(string enabled, string show){
//do stuff
}
Then you get your nodes however you wish. For example this gives me a list of public methods:
IEnumerable<MethodDeclarationSyntax> methods = from m in root.DescendantNodes().OfType<MethodDeclarationSyntax>() where m.Modifiers.ToString().Contains("public") select m;
Then I can iterate through that list of methods to get at the method's ParameterList property which is exposed to make this operation really easy. By the end of this loop the list parameters will hold the names of each parameter in the method (in the example of the Debug method above it will hold the values enabled and show as expected):
var parameters = new List<string>();
foreach (var method in methods)
{
foreach (var n in method.ParameterList.Parameters)
{
var parameterName = n.Identifier.Text;
parameters.Add(parameterName);
}
}
You can search the syntax tree of the reference at the specific source location it occurs to find the node you are looking for. You'll need to use a call like DescendentNodes from the tree's root node and you'll probably need to request the language specific node type you are looking for. Once you have the node in the referecing tree you can then use that tree's semantic model to tell you other information about the arguments.