Roslyn - replace node and fix the whitespaces - code-formatting

In my program I use Roslyn and I need to replace a node with a new node. For example, if I have code like
public void Foo()
{
for(var i = 0; i < 5; i++)
Console.WriteLine("");
}
and I want to insert brackes for for statement, I get
public void Foo()
{
for(var i = 0; i < 5; i++)
{
Console.WriteLine("");
}
}
I tried to use NormalizeWhitespace, but if I use it on for statement, I get
public void Foo()
{
for(var i = 0; i < 5; i++)
{
Console.WriteLine("");
}
}
However, I'd like to have for statement formatted correctly. Any hints how to do it?
EDIT:
I solved it by using:
var blockSyntax = SyntaxFactory.Block(
SyntaxFactory.Token(SyntaxKind.OpenBraceToken).WithLeadingTrivia(forStatementSyntax.GetLeadingTrivia()).WithTrailingTrivia(forStatementSyntax.GetTrailingTrivia()),
syntaxNodes,
SyntaxFactory.Token(SyntaxKind.CloseBraceToken).WithLeadingTrivia(forStatementSyntax.GetLeadingTrivia()).WithTrailingTrivia(forStatementSyntax.GetTrailingTrivia())
);
However, the answer from Sam is also correct.

You need to use .WithAdditionalAnnotations(Formatter.Annotation), but only on the specific element you want to format. Here's an example from the NullParameterCheckRefactoring project.
IfStatementSyntax nullCheckIfStatement = SyntaxFactory.IfStatement(
SyntaxFactory.Token(SyntaxKind.IfKeyword),
SyntaxFactory.Token(SyntaxKind.OpenParenToken),
binaryExpression,
SyntaxFactory.Token(SyntaxKind.CloseParenToken),
syntaxBlock, null).WithAdditionalAnnotations(Formatter.Annotation, Simplifier.Annotation);

Related

ArrayList Method Returns a null ArrayList, main program cannot access

I'm trying to create a basic function that calls on a method that creates the 2D ArrayList that will be used further in the main program to do things like calculate the row and column sums as well as print out the triangle.
However, after it runs the ArrayList returns null. What's going on?
Thanks,
public class Trib
{
private ArrayList<ArrayList<Integer>> triangle;
private int Asize;
public Trib (int size)
{
// convert the argument to type 'int' to be used in the program
Asize = size;
// create an ArrayList of ArrayLists, it will have 'size' number ArrayLists contained within
ArrayList<ArrayList<Integer>> triangle = new ArrayList<ArrayList<Integer>>(size);
// create the inner ArrayLists
for (int i = 0; i < size; i++)
{
// add to index 'i' of our ArrayList a new ArrayList of size (i+1)
triangle.add(new ArrayList<Integer>(i+1));
for (int j = 0; j <= i; j++)
{
if (j==0 || j == i)
{
triangle.get(i).add(1);
}
else
triangle.get(i).add(triangle.get(i-1).get(j-1)+triangle.get(i-1).get(j));
System.out.print(triangle.get(i).get(j) + " ");
}
System.out.println();
}
triangle.clone();
}
public void printTriangle()
{
System.out.print(triangle.get(1).get(1));
/*for (int i = 0; i < Asize; i++)
{
for (int j = 0; j <= i; j++)
{
System.out.print(triangle.get(1).get(1) + " ");
}
System.out.println();
}*/
}
/*public Trib()
{
this(5);
}*/
/*public int Psize()
{
return triangle.size();
}
public ArrayList<Integer> sumRows()
{
ArrayList<Integer> row_sum = new ArrayList<Integer>(Asize);
for (int i = 0; i < Asize; i++)
{
for (int j = 0; j < i; j++)
{
row_sum.add(triangle.get(i).get(j));
}
}
return row_sum;
}
public ArrayList<Integer> sumCols()
{
ArrayList<Integer> col_sum = new ArrayList<Integer>(Asize);
for (int i = 0; i < Asize; i++)
{
for (int j = 0; j < i; j++)
{
col_sum.add(triangle.get(i).get(i));
}
}
return col_sum;
}*/
public static void main(String[] args)
{
if(args.length < 1)
{
System.err.println("Sorry, this program needs an integer argument.");
System.exit(1);
}
Trib pt = new Trib(Integer.parseInt(args[0]));
pt.printTriangle();
//ArrayList<Object> sum_rows = new ArrayList<Object>(pt.Psize());
// sum_rows.add;
System.out.println("\nHere are the sum of rows:");
//for (int i = 0; i < pt.Psize(); i++)
//System.out.println(sum_rows.get(i));
//ArrayList<Integer> sum_cols = new ArrayList<Integer>(pt.Psize());
System.out.println("\nHere are the sum of columns:");
//for (int i = 0; i < pt.Psize(); i++)
//System.out.printf("%-5d", sum_cols.get(i));
}
}
Watch out what's what you are doing: Notice that you have TWO variables named "triangle": The first one is an instance variable and the second is a local variable, which is the only one you have initialized.
My suggestion to avoid this common mistake is to pre-pend "this." to any use of what you intend must be an instance variable. And, if in doubt, if you use a development environment as Eclipse, press CTRL and click on your variable to navigate to the point where it is declared.

Sort array fix code

This method needs to sort and array and I am close with the following code but what it does is puts the list forwards to backwards i.e. if the list was "5, 4, 3" this would change it to "3, 4, 5". This is because after the if statement completes it goes back to the for and once it is finished the for it sets lowest back to 1000. How do I make it not set it back to 1000 each time?
public void sortList()
{
for(int i=0; i<myList.size(); i++)
{
int lowest = 1000;
if(myList.get(i)<lowest)
{
myList.add(0, myList.get(i));
myList.remove(i+1);
}
}
}
This :
public void sortList() {
int lowest = 1000;
for(int i=0; i<myList.size(); i++)
{
if(myList.get(i)<lowest)
{
myList.add(0, myList.get(i));
myList.remove(i+1);
}
}
}
You simply declare lowest outside of the loop, and update it in the loop.
With the example you gave, I would move the 'lowest' declaration out of the for loop, like so:
int lowest = 1000;
for(int i=0; i<myList.size(); i++)
{
if(myList.get(i)<lowest)
{
myList.add(0, myList.get(i));
myList.remove(i+1);
}
}
That way it's not reset to 1000 with each for loop. You can then update it within the loop as needed as you would any other numeric variable.

Add A list Items to Combobox using Dispatcher.BeginInvoke()

I want to add a List to ComboBox through Dispatcher.BeginInvoke. But when I try to put it in a loop, only last value is loading.
private void LoadToComboBox(List<string> msg)
{
for (int i = 0; i < msg.Count; i++)
{
this.Dispatcher.BeginInvoke(() => cmbListItems.Items.Add(msg[i]));
}
}
The Dispatcher.BeginInvoke() is an asynchronous call. What is happening is that by the time you are calling your cmbListItems.Items.Add() function, it is already set to msg.Count.
Try something like this:
private void LoadToComboBox(List<string> msg)
{
this.Dispatcher.BeginInvoke(() =>
{
for (int i = 0; i < msg.Count; i++) {
cmbListItems.Items.Add(msg[i]);
}
});
}

How to transfer ifelse code segment by OOP?

I know that I should break down the method by condition, and implement interface to each subclass, but I do not know how does the client class use it, can you give me simple sample?
public void buildInfoItemUpdater() {
for (int i = 0; i < this.projectInfoInputItemUpdaters.size(); i++) {
if (this.projectInfoInputItemUpdaters.get(i) instanceof ComboBoxUpdater) {
ComboBoxUpdater tempItem = (ComboBoxUpdater) this.projectInfoInputItemUpdaters.get(i);
projectInfoInputItemUpdaters.get(i).setAnswer(tempItem.getUserAnswer());
} else if (this.projectInfoInputItemUpdaters.get(i) instanceof TextBoxUpdater) {
TextBoxUpdater tempItem = (TextBoxUpdater) this.projectInfoInputItemUpdaters.get(i);
projectInfoInputItemUpdaters.get(i).setAnswer(tempItem.getUserAnswer());
} else if (this.projectInfoInputItemUpdaters.get(i) instanceof TextFieldUpdater) {
TextFieldUpdater tempItem = (TextFieldUpdater) this.projectInfoInputItemUpdaters.get(i);
projectInfoInputItemUpdaters.get(i).setAnswer(tempItem.getUserAnswer());
}
}
}
Thank you in advance.
As suggested by #SirPentor, if the Updater classes have a common base class (lets call it UpdaterBase), then define the getUserAnswer() method there, most likely as abstract.
Then you could simplify buildInfoItemUpdater() as follows:
public void buildInfoItemUpdater() {
for (int i = 0; i < this.projectInfoInputItemUpdaters.size(); i++) {
UpdaterBase tempItem =
(UpdaterBase) this.projectInfoInputItemUpdaters.get(i);
projectInfoInputItemUpdaters.get(i).setAnswer(tempItem.getUserAnswer());
}
}
Additionally, whats the difference between this.projectInfoInputItemUpdaters.get(i) and projectInfoInputItemUpdaters.get(i)? Seems like your calling get() twice on the same object, right? You may be able to simplify this part as well.

NHibernate: Saving different types of objects in the same session breaks batching

newbie here, sorry if this is an obvious question.
It seems saving different types of objects in the same session breaks batching, cause significant performance drop.
ID generator is set to Increment (as Diego Mijelshon advised, I tried hilo("100"), but unfortunately same issue, Test1() is still about 5 times slower than Test2()):
public class CustomIdConvention : IIdConvention
{
public void Apply(IIdentityInstance instance)
{
instance.GeneratedBy.Increment();
}
}
AdoNetBatchSize is set to 1000:
MsSqlConfiguration.MsSql2008
.ConnectionString(connectionString)
.AdoNetBatchSize(1000)
.Cache(x => x
.UseQueryCache()
.ProviderClass<HashtableCacheProvider>())
.ShowSql();
These are the models:
public class TestClass1
{
public virtual int Id { get; private set; }
}
public class TestClass2
{
public virtual int Id { get; private set; }
}
These are the test methods. Test1() takes 62 seconds, Test2() takes only 11 seconds. (as Phill advised, I tried stateless sessions, but unfortunately same issue):
[TestMethod]
public void Test1()
{
int count = 50 * 1000;
using (var session = SessionFactory.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
for (int i = 0; i < count; i++)
{
var x = new TestClass1();
var y = new TestClass2();
session.Save(x);
session.Save(y);
}
transaction.Commit();
}
}
}
[TestMethod]
public void Test2()
{
int count = 50 * 1000;
using (var session = SessionFactory.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
for (int i = 0; i < count; i++)
{
var x = new TestClass1();
session.Save(x);
}
transaction.Commit();
}
}
using (var session = SessionFactory.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
for (int i = 0; i < count; i++)
{
var y = new TestClass2();
session.Save(y);
}
transaction.Commit();
}
}
}
Any ideas?
Thanks!
Update:
The test project can be downloaded from here. You need to change the connectionString in the Main method. I changed all sessions to stateless sessions.
My restuls: Test1 = 59.11, Test2 = 7.60, Test3 = 7.72. Test1 is 7.7 times slower than Test2 & Test3!
Do not use increment. It's the worst possible generator.
Try changing it to HiLo.
Update:
It looks like the problem occurs when alternating saves of different entities, regardless of whether the session/transaction are separated or not.
This produces similar results to the second test method:
[TestMethod]
public void Test3()
{
int count = 50 * 1000;
using (var session = SessionFactory.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
for (int i = 0; i < count; i++)
{
var x = new TestClass1();
session.Save(x);
}
for (int i = 0; i < count; i++)
{
var y = new TestClass2();
session.Save(y);
}
transaction.Commit();
}
}
}
My guess, without looking at NH's sources, is that it preserves the order because of possible relationships between the entities, even when there are none.
When you run test2 and test3, the insert's are batched together.
When you run test1, where you alternate the inserts, the inserts are issued as separate statements and are not batched together.
I found this out by profiling all three tests.
So as per Diego's answer, it must preserve the order that you're inserting, and batch them together.
I wrote a 4th test, I set the batch size to 10, then alternated when i changed from TestClass1 to TestClass2 so that I was doing 5 of TestClass1 and then 5 of TestClass2, to hit the batch size.
This pushed out batch's of 5 in the order they were processed.
public void Test4()
{
int count = 10;
using (var session = SessionFactory.OpenSession())
using (var transaction = session.BeginTransaction())
{
for (int i = 0; i < count; i++)
{
if (i%2 == 0)
{
for (int j = 0; j < 5; j++)
{
var x = new TestClass1();
session.Save(x);
}
}
else
{
for (int j = 0; j < 5; j++)
{
var y = new TestClass2();
session.Save(y);
}
}
}
transaction.Commit();
}
}
Then I changed it to insert 3 at a time instead of 5. The batch's were in multiples of 3, so what must be happening is the batch size allows a batch of 1 type to go to specified amount, but groups only the same type together. While alternating causes separate insert statements.