I am sorry if the title for my question is not apt.
I am a newbie to the programming side and trying to write a console app for getting all the installed apps on the computer from registry.
Here is my code.
class Program
{
static void Main(string[] args)
{
Console.Title = "Windows App Finder - Finds all the installed apps on the station";
List<AppDetails> apps = new List<AppDetails>();
apps = GetInstalledApps();
ListAllApps(apps);
Console.WriteLine("\nPress any key to exit.");
Console.ReadLine();
}
private static List<AppDetails> GetInstalledApps()
{
string registry_key = #"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
AppDetails appInfo = new AppDetails();
List<AppDetails> apps = new List<AppDetails>();
using (Microsoft.Win32.RegistryKey key = Registry.LocalMachine.OpenSubKey(registry_key))
{
foreach (string subkey_name in key.GetSubKeyNames())
{
using (RegistryKey subkey = key.OpenSubKey(subkey_name))
{
appInfo.appName = (string)subkey.GetValue("DisplayName");
appInfo.publisher = (string)subkey.GetValue("Publisher");
appInfo.appVersion = (string)subkey.GetValue("DisplayVersion");
if (appInfo.appName != null )
{
apps.Add(appInfo);
}
}
}
}
return apps;
}
private static void ListAllApps(List<AppDetails> appDetails)
{
int i = 0;
foreach (AppDetails appDetail in appDetails)
{
Console.WriteLine(i.ToString() + ". Name: " + appDetail.appName + " Version: " + appDetail.appVersion + " Publisher: " + appDetail.publisher);
i++;
}
}
}
public class AppDetails
{
public string appName { get; set; }
public string appVersion {get; set;}
public string publisher {get;set;}
public DateTime installDate { get; set; }
}
}
This code returns http://i.stack.imgur.com/tKtNr.png
Single app name repeated multiple times. What is wrong with this piece of code.
Thanks in advance
You have to instantiate AppDetails appInfo = new AppDetails(); inside your foreach loop, otherwise you will end with same object getting modified and added to the List again and again.
Just move the instantiation to inside your loop.
private static List<AppDetails> GetInstalledApps()
{
string registry_key = #"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
List<AppDetails> apps = new List<AppDetails>();
using (Microsoft.Win32.RegistryKey key = Registry.LocalMachine.OpenSubKey(registry_key))
{
foreach (string subkey_name in key.GetSubKeyNames())
{
using (RegistryKey subkey = key.OpenSubKey(subkey_name))
{
AppDetails appInfo = new AppDetails(); //HERE
appInfo.appName = (string)subkey.GetValue("DisplayName");
appInfo.publisher = (string)subkey.GetValue("Publisher");
appInfo.appVersion = (string)subkey.GetValue("DisplayVersion");
if (appInfo.appName != null)
{
apps.Add(appInfo);
}
}
}
}
return apps;
}
Since you are not instantiating the object inside the loop, It is being added to list multiple times, and all the instance in the list points to same reference. Therefore you see the same values returned multiple times. It would be the last value in your iteration.
Related
I am trying to get the object value but I don't know how to do it. I'm new to C# and its giving me syntax error. I want to print it separately via the method "PrintSample" How can I just concatenate or append the whatData variable . Thank you.
PrintSample(getData, "name");
PrintSample(getData, "phone");
PrintSample(getData, "address");
//Reading the CSV file and put it in the object
string[] lines = File.ReadAllLines("sampleData.csv");
var list = new List<Sample>();
foreach (var line in lines)
{
var values = line.Split(',');
var sampleData = new Sample()
{
name = values[0],
phone = values[1],
address = values[2]
};
list.Add(sampleData);
}
public class Sample
{
public string name { get; set; }
public string phone { get; set; }
public string adress { get; set; }
}
//Method to call to print the Data
private static void PrintSample(Sample getData, string whatData)
{
//THis is where I'm having error, how can I just append the whatData to the x.?
Console.WriteLine( $"{getData. + whatData}");
}
In C# it's not possible to dynamically evaluate expression like
$"{getData. + whatData}"
As opposed to languages like JavaScript.
I'd suggest to use rather switch expression or Dictionary<string, string>
public void PrintData(Sample sample, string whatData)
{
var data = whatData switch
{
"name" => sample.name,
"phone" => sample.phone,
"address" => sample.address
_ => throw new ArgumentOutOfRangeException(nameof(whatData)),
};
Console.WriteLine(data);
}
I'm not sure what you are trying to achieve. Perhaps this will help you:
private static void PrintSample(Sample getData, string whatData)
{
var property = getData.GetType().GetProperty(whatData);
string value = (string)property?.GetValue(getData) ?? "";
Console.WriteLine($"{value}");
}
What PO really needs is
private static void PrintSamples(List<Sample> samples)
{
foreach (var sample in samples)
Console.WriteLine($"name : {sample.name} phone: {sample.phone} address: {sample.address} ");
}
and code
var list = new List<Sample>();
foreach (var line in lines)
{
......
}
PrintSamples(list);
it is radicolous to use
PrintSample(getData, "name");
instead of just
PrintSample(getData.name)
You can do this using reflection. However, it's known to be relatively slow.
public static void PrintSample(object getData, string whatData)
{
Console.WriteLine( $"{getData.GetType().GetProperty(whatData).GetValue(getData, null)}");
}
This question already has answers here:
Help someone new to C# variables
(5 answers)
Closed 2 years ago.
In my current application while I have been able to implement the required logic that I need I am really stuck when trying to take off the content from the main method and using it from a different method .
My code is as below,
class Program
{
const string path = #"filePath";
static void Main(string[] args)
{
setUpValues();
}
private static void setUpValues()
{
var Content = JsonConvert.DeserializeObject<deploy>(File.ReadAllText(path));
List<Variable> variables = Content.Variables.ToList();
Scopes Scope = Content.ScopeValues;
string Version = null;
List<string> ListOfSelectedItems= new List<string>();
List<string> TempListOfSelectedItems = new List<string>();
List<string> Channels = new List<string>();
foreach (var item in variables)
{
if (item.Name.Equals("version"))
{
Version = item.Value;
}
if (item.Name.Equals("Selected"))
{
TempListOfSelectedItems.Add(item.Value);
}
}
Console.WriteLine("Version " + Version);
Console.WriteLine();
string SelectedItems= TempListOfSelectedItems[0];
ListOfSelectedItems = SelectedItems.Split(',').ToList();
Console.WriteLine();
Console.WriteLine("Selected Modules");
Console.WriteLine();
foreach (var item in ListOfSelectedItems)
{
Console.WriteLine(item);
}
foreach (var item in Scope.Channels)
{
Channels.Add(item.Name);
}
}
}
I want to be able to access the variable string Version , the List of ListOfSelectedItems and the List of channels from outside this method .. I want to use these in another as well . So how can I make these globally accessible ?
Would really appreciate your help on this as I have been stuck here
In order to use variables outside a method, you should declare them as fields of a class. Like this:
class Program
{
const string path = #"filePath";
static deploy Content;
static string Version;
static List<string> ListOfSelectedItems;
static List<string> TempListOfSelectedItems;
static List<string> Channels;
// and others
static void Main(string[] args)
{
setUpValues();
}
private static void setUpValues()
{
Content = JsonConvert.DeserializeObject<deploy>(File.ReadAllText(path));
List<Variable> variables = Content.Variables.ToList();
Scopes Scope = Content.ScopeValues;
Version = null;
ListOfSelectedItems = new List<string>();
TempListOfSelectedItems = new List<string>();
Channels = new List<string>();
foreach (var item in variables)
{
if (item.Name.Equals("version"))
{
Version = item.Value;
}
if (item.Name.Equals("Selected"))
{
TempListOfSelectedItems.Add(item.Value);
}
}
Console.WriteLine("Version " + Version);
Console.WriteLine();
string SelectedItems = TempListOfSelectedItems[0];
ListOfSelectedItems = SelectedItems.Split(',').ToList();
Console.WriteLine();
Console.WriteLine("Selected Modules");
Console.WriteLine();
foreach (var item in ListOfSelectedItems)
{
Console.WriteLine(item);
}
foreach (var item in Scope.Channels)
{
Channels.Add(item.Name);
}
}
}
You have to declare those fields as static because they are used in a static method. After the setUpValues finishes running, you can use those fields inside the Main method as well.
Also, this is not related to the question, but the general code convention in C# is to start methods' names with an uppercase letter (so SetUpValues instead of setUpValues) and to start the local variables' names with a lowercase letter (selectedItems instead of SelectedItems). Obviously, it's ultimately up to you how to name things and which code convention to use.
Create a class with properties that you want to access from other places. Instantiate this class in setUpValues and return this.
public class TestClass
{
public TestClass()
{
this.ListOfSelectedItems = new List<string>();
}
public string Version { get; set; }
public List<string> ListOfSelectedItems { get; set; }
}
And then modify your Main method as:
var myObj = setUpValues();
And then Modify setUpValues to return this:
private static TestClass setUpValues()
{
var Content = JsonConvert.DeserializeObject<deploy>(File.ReadAllText(path));
List<Variable> variables = Content.Variables.ToList();
Scopes Scope = Content.ScopeValues;
string Version = null;
List<string> ListOfSelectedItems = new List<string>();
List<string> TempListOfSelectedItems = new List<string>();
List<string> Channels = new List<string>();
foreach (var item in variables)
{
if (item.Name.Equals("version"))
{
Version = item.Value;
}
if (item.Name.Equals("Selected"))
{
TempListOfSelectedItems.Add(item.Value);
}
}
var retObj = new TestClass();
Console.WriteLine("Version " + Version);
Console.WriteLine();
retObj.Version = Version;
string SelectedItems = TempListOfSelectedItems[0];
ListOfSelectedItems = SelectedItems.Split(',').ToList();
Console.WriteLine();
Console.WriteLine("Selected Modules");
Console.WriteLine();
foreach (var item in ListOfSelectedItems)
{
Console.WriteLine(item);
retObj.ListOfSelectedItems.Add(item);
}
foreach (var item in Scope.Channels)
{
Channels.Add(item.Name);
}
return retObj;
}
I'm accessing a value object as follows: accounts[accountNum]
I want to do some minor manipulation on this object, ie: increase it by something, etc. Rather than typing "accounts[accountNum] += something" I'd rather do something like this:
MemberData account = accounts[accountNum];
account.balance += something;
Ie: "account" should be a direct pointer, reference, or somehow "be equivalent to" typing "accounts[accountNum]". But since this is a value type and not a reference type, it makes a copy and I cannot manipulate that object directly.
All my research on using "ref" seems to talk about using it within method parameters and return types, not in variables. Is there a simple way to shortcut a long variable name whilst still referencing the same object?
UPDATE:
Full source code - Please see specifically Line 46 & 51
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
/* * Description of the project:
* To implement an ATM machine which accepts deposits, withdrawals
* DEPOSIT / WITHDRAWAL:
* Account, Amount, Timestamp, TransactionID, Location
* Keep record of all accounts in TXT file, which is updated after each transaction. Of course in live system DB would be used.
* Keep another file that logs all transactions. Make it possible to LINQ the log associated with account, to show transaction history.
* TXT Accounts in form of:
* Account #, Name, Balance
* */
namespace ATMProject
{
class Program
{
static void Main(string[] args)
{
// Globals.DisplayAccounts();
// Deposit.MakeDeposit(1000009, 500, "sydney");
}
}
static class Deposit
{
//TODO Deposit: * Account #, Amount, Timestamp, TransactionID, Location
public static void MakeDeposit(long accountNum, long amount, string location)
{
string timestamp;
string transactionID;
timestamp = DateTime.Now.ToString("yyyyMMddhhmm");
transactionID = Globals.GenerateValidTransactionID();
using (StreamWriter sr = new StreamWriter(Globals.transactions, true))
{
string transactString = $"DEPOSIT| {accountNum}| {amount}| {timestamp}| {transactionID}| {location}";
sr.WriteLine(transactString);
}
Globals.WriteTransactionID(transactionID);
Dictionary<long, MemberData> accounts = Globals.GenerateAccounts();
try
{
//WORKS
MemberData account = accounts[accountNum];
account.balance += amount;
accounts[accountNum] = account;
//DOESN'T BUILD
//ref MemberData account = ref accounts[accountNum];
}
catch (KeyNotFoundException)
{
Console.WriteLine("Deposit failed, selected account number does not exist in accounts.txt");
}
}
}
static class Withdraw
{
}
static class CreateAccount
{
public static void Create(string name, long StartDeposit)
{
long accountNumber;
using (StreamReader sr = new StreamReader(Globals.accountIter))
{
accountNumber = Convert.ToInt64(sr.ReadLine());
sr.Close();
}
using (StreamWriter sr = new StreamWriter(Globals.accounts, true))
{
string accountAdd = $"{accountNumber}| {name}| {StartDeposit}";
sr.WriteLine(accountAdd);
Globals.SetNextAccountNumber();
Console.WriteLine("Successfully created account #" + accountNumber);
sr.Close();
}
}
}
struct MemberData
{
public long accountNum;
public string name;
public long balance;
public MemberData(long accountNum, string name, long balance)
{
this.accountNum = accountNum;
this.name = name;
this.balance = balance;
}
public override string ToString()
{
string thisStr = $"Account #: {accountNum}, Name: {name}, Balance: {balance}";
return thisStr;
}
}
static class Globals
{
public static string basepath = "C:\\Users\\root\\RiderProjects\\ConsoleApp1\\ATMProject\\";
public static string accounts = basepath + "accounts.txt"; //path to all accounts
public static string transactions = basepath + "transactions.txt"; //path to all accounts
public static string accountIter = basepath + "accountIter.txt"; //path to the current account iter
public static string transactIter = basepath + "transactIter.txt"; //path to the current account iter
//class values
public static long GetNextAccountNumber() //returns the next available account #
{
try
{
using (StreamReader sr = new StreamReader(accountIter))
{
long currAccountIter = Convert.ToInt64(sr.ReadLine());
sr.Close();
return currAccountIter;
}
}
catch (IOException e)
{
Console.WriteLine(e.Message);
return -1;
}
}
public static void SetNextAccountNumber() //increments the account #
{
long currAccountIter = GetNextAccountNumber();
if (currAccountIter == -1)
{
Console.WriteLine("Could not SetNextAccountNumber");
return;
}
using (StreamWriter sr = new StreamWriter(accountIter, false))
{
currAccountIter += 1;
sr.WriteLine(currAccountIter);
sr.Close();
}
}
public static Dictionary<long, MemberData> GenerateAccounts() //Returns Dictionary in form of <Account Number, MemberData>
{
Dictionary<long, MemberData> memberList = new Dictionary<long, MemberData>();
using (StreamReader sr = new StreamReader(accounts))
{
while (!sr.EndOfStream)
{
var memberSplit = sr.ReadLine().Split("| ", StringSplitOptions.RemoveEmptyEntries);
long accountNum = Convert.ToInt64(memberSplit[0]);
string name = memberSplit[1];
long balance = Convert.ToInt64(memberSplit[2]);
MemberData member = new MemberData(accountNum, name, balance);
memberList.Add(accountNum, member);
}
}
return memberList;
}
public static void DisplayAccounts()
{
Console.WriteLine("List of all Accounts:\n===========");
foreach (var member in GenerateAccounts())
{
Console.WriteLine(member.Value);
}
}
public static string GetTimestamp()
{
string timestamp = DateTime.Now.ToString("yyyyMMddhhmmss");
return timestamp;
}
private static string GetTransactionIter()
{
using (StreamReader sr = new StreamReader(transactIter))
{
string transactionID = sr.ReadLine();
sr.Close();
return transactionID;
}
}
public static string GenerateValidTransactionID()
{
string IDPart;
string timestamp = GetTimestamp();
string transactionID = GetTransactionIter();
string numberSlice = transactionID.Substring(14);
string timestampSlice = transactionID.Substring(0, 14);
if (timestamp == timestampSlice)
{
IDPart = Convert.ToString(Convert.ToInt64(numberSlice) + 1);
transactionID = timestamp + IDPart;
}
else
{
transactionID = timestamp + 0;
}
return transactionID;
}
public static void WriteTransactionID(string transactionID) //overwrite and write current transactionID to iter
{
using (StreamWriter sr = new StreamWriter(transactIter, false))
{
sr.WriteLine(transactionID);
sr.Close();
}
}
public static void GenereateAndWriteTransactionID()
{
WriteTransactionID(GenerateValidTransactionID());
}
}
}
Since C# 7 you can use local ref variables:
ref int niceName = ref localVariable.Values.SubArray.Here;
niceName += 20;
Note that you can not use this in async methods. And it does neither work with properties nor indexers (except for arrays).
In device manager of windows7 in com port's branch I choose menu "properties" one of port. In tab of "details" I chose property "parent" and see the string:
How I can obtain this string from vb .net or another language in visual studio in cmd also will be good?
I tried to use win32_ clases: pnpentity, serialPort etc but this no solved to my problem even output of Get-WMIObject Win32_SerialPort in PS had not property "parent".
Dim objService = GetObject("winmgmts://./root/cimv2")
For Each objPort In objService.ExecQuery("SELECT * FROM Win32_PnPEntity WHERE ClassGuid='{4d36e978-e325-11ce-bfc1-08002be10318}'")
Console.WriteLine(objPort.Caption & vbCrLf)
Console.Write(objPort.DeviceID & vbCrLf)
Console.ReadLine()
Next
Except Device ID I try Caption and all syntax that available in List.
Do you have any idea, please?
My solution was the following:
Get all active ports with their PnpDeviceIds:
private static List<PortInfo> GetActivePorts()
{
var ports = new List<PortInfo>();
using (var searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_SerialPort"))
using (var collection = searcher.Get())
{
foreach (var device in collection)
{
var portInfo = new PortInfo
{
Port = (string)device.GetPropertyValue("DeviceID"),
PnPDeviceId = (string)device.GetPropertyValue("PNPDeviceID")
};
if (!string.IsNullOrEmpty(portInfo.Port) && !string.IsNullOrEmpty(portInfo.PnPDeviceId))
{
ports.Add(portInfo);
}
}
}
return ports;
}
where PortInfo is
private class PortInfo
{
public string Port { get; set; }
public string PnPDeviceId { get; set; }
public string ParentDeviceId { get; set; }
}
fill ParentDeviceIds :
private static async void FillParentIds(IReadOnlyCollection<PortInfo> ports)
{
var propertiesToQuery = new List<string> {
"System.Devices.DeviceInstanceId",
"System.Devices.Parent"
};
var aqs = string.Join(" OR ", ports.Select(p => $"System.Devices.DeviceInstanceId:={p.PnPDeviceId}"));
var pnpDevices = await PnpObject.FindAllAsync(PnpObjectType.Device, propertiesToQuery, aqs);
foreach (var pnpDevice in pnpDevices)
{
var port = ports.FirstOrDefault(p => string.Compare(p.PnPDeviceId, pnpDevice.Id, StringComparison.InvariantCultureIgnoreCase) == 0);
if (port != null && pnpDevice.Properties.TryGetValue("System.Devices.Parent", out var parentId))
{
port.ParentDeviceId = parentId?.ToString();
}
}
}
ParentDeviceId will be that string you are looking for.
While exploring Roslyn I put together a small app that should include a trace statement as the first statement in every method found in a Visual Studio Solution. My code is buggy and is only updating the first method.
The line that is not working as expected is flagged with a “TODO” comment. Please, advise.
I also welcome style recommendations that would create a more streamlined/readable solution.
Thanks in advance.
...
private void TraceBtn_Click(object sender, RoutedEventArgs e) {
var myWorkSpace = new MyWorkspace("...Visual Studio 2012\Projects\Tests.sln");
myWorkSpace.InjectTrace();
myWorkSpace.ApplyChanges();
}
...
using System;
using System.Linq;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;
using Roslyn.Services;
namespace InjectTrace
{
public class MyWorkspace
{
private string solutionFile;
public string SolutionFile {
get { return solutionFile; }
set {
if (string.IsNullOrEmpty(value)) throw new Exception("Invalid Solution File");
solutionFile = value;
}
}
private IWorkspace loadedWorkSpace;
public IWorkspace LoadedWorkSpace { get { return loadedWorkSpace; } }
public ISolution CurrentSolution { get; private set; }
public IProject CurrentProject { get; private set; }
public IDocument CurrentDocument { get; private set; }
public ISolution NewSolution { get; private set; }
public MyWorkspace(string solutionFile) {
this.SolutionFile = solutionFile;
this.loadedWorkSpace = Workspace.LoadSolution(SolutionFile);
}
public void InjectTrace()
{
int projectCtr = 0;
int documentsCtr = 0;
int transformedMembers = 0;
int transformedClasses = 0;
this.CurrentSolution = this.LoadedWorkSpace.CurrentSolution;
this.NewSolution = this.CurrentSolution;
//For Each Project...
foreach (var projectId in LoadedWorkSpace.CurrentSolution.ProjectIds)
{
CurrentProject = NewSolution.GetProject(projectId);
//..for each Document in the Project..
foreach (var docId in CurrentProject.DocumentIds)
{
CurrentDocument = NewSolution.GetDocument(docId);
var docRoot = CurrentDocument.GetSyntaxRoot();
var newDocRoot = docRoot;
var classes = docRoot.DescendantNodes().OfType<ClassDeclarationSyntax>();
IDocument newDocument = null;
//..for each Class in the Document..
foreach (var #class in classes) {
var methods = #class.Members.OfType<MethodDeclarationSyntax>();
//..for each Member in the Class..
foreach (var currMethod in methods) {
//..insert a Trace Statement
var newMethod = InsertTrace(currMethod);
transformedMembers++;
//TODO: PROBLEM IS HERE
newDocRoot = newDocRoot.ReplaceNode(currMethod, newMethod);
}
if (transformedMembers != 0) {
newDocument = CurrentDocument.UpdateSyntaxRoot(newDocRoot);
transformedMembers = 0;
transformedClasses++;
}
}
if (transformedClasses != 0) {
NewSolution = NewSolution.UpdateDocument(newDocument);
transformedClasses = 0;
}
documentsCtr++;
}
projectCtr++;
if (projectCtr > 2) return;
}
}
public MethodDeclarationSyntax InsertTrace(MethodDeclarationSyntax currMethod) {
var traceText =
#"System.Diagnostics.Trace.WriteLine(""Tracing: '" + currMethod.Ancestors().OfType<NamespaceDeclarationSyntax>().Single().Name + "." + currMethod.Identifier.ValueText + "'\");";
var traceStatement = Syntax.ParseStatement(traceText);
var bodyStatementsWithTrace = currMethod.Body.Statements.Insert(0, traceStatement);
var newBody = currMethod.Body.Update(Syntax.Token(SyntaxKind.OpenBraceToken), bodyStatementsWithTrace,
Syntax.Token(SyntaxKind.CloseBraceToken));
var newMethod = currMethod.ReplaceNode(currMethod.Body, newBody);
return newMethod;
}
public void ApplyChanges() {
LoadedWorkSpace.ApplyChanges(CurrentSolution, NewSolution);
}
}
}
The root problem of you code is that newDocRoot = newDocRoot.ReplaceNode(currMethod, newMethod); somehow rebuilds newDocRoot internal representation of code so next currMethod elements won't be find in it and next ReplaceNode calls will do nothing. It is a situation similar to modifying a collection within its foreach loop.
The solution is to gather all necessary changes and apply them at once with ReplaceNodes method. And this in fact naturally leads to simplification of code, because we do not need to trace all those counters. We simply store all needed transformation and apply them for whole document at once.
Working code after changes:
public void InjectTrace()
{
this.CurrentSolution = this.LoadedWorkSpace.CurrentSolution;
this.NewSolution = this.CurrentSolution;
//For Each Project...
foreach (var projectId in LoadedWorkSpace.CurrentSolution.ProjectIds)
{
CurrentProject = NewSolution.GetProject(projectId);
//..for each Document in the Project..
foreach (var docId in CurrentProject.DocumentIds)
{
var dict = new Dictionary<CommonSyntaxNode, CommonSyntaxNode>();
CurrentDocument = NewSolution.GetDocument(docId);
var docRoot = CurrentDocument.GetSyntaxRoot();
var classes = docRoot.DescendantNodes().OfType<ClassDeclarationSyntax>();
//..for each Class in the Document..
foreach (var #class in classes)
{
var methods = #class.Members.OfType<MethodDeclarationSyntax>();
//..for each Member in the Class..
foreach (var currMethod in methods)
{
//..insert a Trace Statement
dict.Add(currMethod, InsertTrace(currMethod));
}
}
if (dict.Any())
{
var newDocRoot = docRoot.ReplaceNodes(dict.Keys, (n1, n2) => dict[n1]);
var newDocument = CurrentDocument.UpdateSyntaxRoot(newDocRoot);
NewSolution = NewSolution.UpdateDocument(newDocument);
}
}
}
}