So I'm experimenting with the new ISourceGenerator system to generate a few I18n strings & classes from XML files. This works but now I want to extend an existing partial class using a source generator, but whenever I do the original class contents become inaccessible! This is the class I have:
// File: Strings.cs
namespace MyProject.I18n
{
public static partial class Strings
{
public const string Options = "Options";
}
}
This is what I'm generating:
// Generated file: GeneratedStrings.cs
namespace MyProject.I18n
{
public static partial class Strings
{
public const string MainMenu = "Main menu";
}
}
This is how I'm generating it (MVCE):
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
[Generator]
public class I18NGenerator : ISourceGenerator
{
private const string XML_EXAMPLE = #"
<Strings>
<MainMenu>Main menu</MainMenu>
</Strings>
";
private StringBuilder sb = null!;
private int indentation;
public void Initialize(GeneratorInitializationContext context)
{
sb = new StringBuilder();
indentation = 0;
}
public void Execute(GeneratorExecutionContext context)
{
var root = XDocument.Parse(XML_EXAMPLE).Root!;
void Process(XElement element)
{
var text = element.Nodes().FirstOrDefault(node => node is XText);
if (text is XText xText)
{
IndentedLn($#"public static string {element.Name.LocalName} = ""{xText.Value}"";");
}
else
{
BeginBlock($"public static partial class {element.Name.LocalName}");
foreach (var xElement in element.Elements())
Process(xElement);
EndBlock();
}
}
BeginBlock("namespace MyProject.I18n");
Process(root);
EndBlock();
context.AddSource("GeneratedStrings.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
}
private void Indent()
{
indentation++;
}
private void Dedent()
{
indentation--;
}
private void BeginBlock(string statement = "")
{
if (statement.Length != 0)
IndentedLn(statement);
IndentedLn("{");
Indent();
}
private void EndBlock()
{
Dedent();
IndentedLn("}");
}
private void Raw(string text) => sb.Append(text);
private void Indented(string code)
{
for (var i = 0; i < indentation; i++)
Raw("\t");
Raw(code);
}
private void IndentedLn(string code) => Indented(code + "\n");
}
Trying to access Strings.Options gives the compilation error 'Strings' does not contain a definition for 'Options'.
I can add that if I generate BOTH files they merge just fine.
Related
Here's the thing: I want to get the string named "IPAddress" from FullParse.cs to Form1.cs. What would it be if I'll get multiple variables aside from "IPAddress"?
Here's the code I've made
FullParse.cs
using RestSharp;
namespace WindowsFormsApp2
{
internal class FullParse
{
public void getIP() {
RestClient client = new RestClient("http://ip-api.com/json/?fields=9009");
var request = new RestRequest(Method.GET);
IRestResponse response = client.Execute(request);
string source = (response.Content);
dynamic data = JObject.Parse(source);
string IPAddress = data.query;
}
}
}
Form1.cs
using System.Windows.Forms;
namespace WindowsFormsApp2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
FullParse fullParse = new FullParse();
}
}
}
It's still my first time using C# especially OOP so I don't really know if i'm doing this right.
Example of one way you can do this with multiple out parameters:
Changes to FullParse.cs:
using RestSharp;
namespace WindowsFormsApp2
{
internal class FullParse
{
public string getIP(out int firstOutInt, out string secondOutString) {
RestClient client = new RestClient("http://ip-api.com/json/?fields=9009");
var request = new RestRequest(Method.GET);
IRestResponse response = client.Execute(request);
string source = (response.Content);
dynamic data = JObject.Parse(source);
string IPAddress = data.query;
int firstOutInt = 1234;
string secondOutString = "some text";
return IPAddress;
}
}
}
Changes to Form1.cs:
using System.Windows.Forms;
namespace WindowsFormsApp2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
FullParse fullParse = new FullParse();
string ipAddress = fullParse.getIP(out int firstOutInt, out string secondOutString);
//doSomething is not defined here - this is just an example of a function using the values from getIP
doSomething(ipAddress, firstOutInt, secondOutString);
}
}
}
The following demo application on MEF technology does not work.
Can't build the simplest extensible application. I started with the simplest, a console application that will simply display text on the screen according to the specified parameters. And even here he did not go to me. Where to dig?
IDemoInterface.cs
public interface IDemoInretface
{
void Run(int sleep, int count);
}
MEFDataDemo
Program.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.IO;
namespace MEFDataDemo
{
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.Run();
}
public void Run()
{
DoImport();
int count = 1;
foreach (var item in Plugin)
{
item.Value.Run(count * 1000, count * 10);*** This is Error
count++;
}
}
[ImportMany(typeof(IDemoInretface))]
public IEnumerable<Lazy<IDemoInretface>> Plugin { get; set; }
public void DoImport()
{
var catalog = new AggregateCatalog();
var path = Path.Combine(Directory.GetCurrentDirectory(), "Plugins");
catalog.Catalogs.Add(new DirectoryCatalog(path));
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
}
Plugin1 Class1.cs
using System;
using System.ComponentModel.Composition;
using System.Threading;
namespace Plugin1
{
[Export(typeof(IDemoInretface))]
internal class Class1 : IDemoInretface
{
public void Run(int sleep, int count)
{
for (int i = 0; i < count; i++)
{
Console.WriteLine("This plugin1 print {0}/{1} in {2}ms", i, count, sleep);
Thread.Sleep(sleep);
}
}
}
}
What am I doing wrong?
The program compiles, but either does not read plugins, or reads but does not run the (RUN) method
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
public class GetAllObjects : MonoBehaviour
{
private void Start()
{
}
private static string GetClickedDirFullPath()
{
string clickedAssetGuid = Selection.assetGUIDs[0];
string clickedPath = AssetDatabase.GUIDToAssetPath(clickedAssetGuid);
string clickedPathFull = Path.Combine(Directory.GetCurrentDirectory(), clickedPath);
FileAttributes attr = File.GetAttributes(clickedPathFull);
return attr.HasFlag(FileAttributes.Directory) ? clickedPathFull : Path.GetDirectoryName(clickedPathFull);
}
private static string GetPath()
{
string path = GetClickedDirFullPath();
int index = path.IndexOf("Assets");
string result = path.Substring(index);
return result;
}
static List<string> paths = new List<string>();
private static void GetFolders()
{
paths = new List<string>();
string selectedPath = GetPath();
string[] assetsPaths = AssetDatabase.GetAllAssetPaths();
foreach (string assetPath in assetsPaths)
{
if (assetPath.Contains(selectedPath))
{
if (assetPath.Contains("Prefabs"))
{
paths.Add(assetPath);
}
}
}
}
[MenuItem("Assets/Add Components")]
public static void AddComponents()
{
GetFolders();
}
}
When I put a brea kpoint in the end of the GetFolders method it shows on the List paths 54 prefabs.
In the editor it shows 45.
Error: error CS0103: The name 'JsonConvert' does not exist in the current context
I have the latest Newtonsoft download and I cant figure out any way to fix this I've gone over about 50 different links all saying to install it. Which it is.
Am I missing something small? I am just trying to add my json elements to a list so I can use them in a program and then write back to the Json file. If this cant work can someone link or show me another way to do this in c#?
using System.IO;
using System.Collections.Generic;
using UnityEngine;
using Newtonsoft.Json;
namespace Newtonsoft.Json {
public class CustomControls : MonoBehaviour
{
private List<string> controls;
//public object JsonConvert { get; private set; }
// Start is called before the first frame update
void Start()
{
LoadJson();
for (int i = 0; i < controls.Count; i++)
{
Debug.Log(controls[i].ToString());
}
}
public void LoadJson()
{
using (StreamReader r = new StreamReader("CustomControls.json"))
{
string json = r.ReadToEnd();
controls = JsonConvert.DeserializeObject<List<string>>(json);
}
}
}
}
Change the name of the namespace in your code
using System.IO;
using System.Collections.Generic;
using UnityEngine;
using Newtonsoft.Json;
namespace AnythingOtherThanNewtonsoft.Json {
public class CustomControls : MonoBehaviour
{
private List<string> controls;
//public object JsonConvert { get; private set; }
// Start is called before the first frame update
void Start()
{
LoadJson();
for (int i = 0; i < controls.Count; i++)
{
Debug.Log(controls[i].ToString());
}
}
public void LoadJson()
{
using (StreamReader r = new StreamReader("CustomControls.json"))
{
string json = r.ReadToEnd();
controls = JsonConvert.DeserializeObject<List<string>>(json);
}
}
}
}
If you want or need to use Newtonsoft.Json for some reason, I highly recommend you this guide.
Else, here is an alternative for your case, in which you can use unity`s JsonUtility.
You only need to wrap it in a class
using System.IO;
using UnityEngine;
using System.Collections.Generic;
public class MyControls{
public List<string> controls;
}
public class CustomControls : MonoBehaviour
{
private MyControls myControls;
void Start()
{
SaveJson();
LoadJson();
for (int i = 0; i < myControls.controls.Count; i++)
{
Debug.Log(myControls.controls[i]);//No need to use ToString() here, it`s already a string
}
}
public void SaveJson()
{
MyControls testControls = new MyControls() //Creates a new instance of MyControls
{
controls = new List<string>(2) {"a", "b"} //Your list of strings should go here.
};
File.WriteAllText("CustomControls.json", JsonUtility.ToJson(testControls));
}
public void LoadJson()
{
using (StreamReader r = new StreamReader("CustomControls.json"))
{
string json = r.ReadToEnd();
myControls = JsonUtility.FromJson<MyControls>(json);
}
}
}
Edit: Added an example on how to save a json file using JsonUtility
The file created have this on it {"controls":["a","b"]}
I'm creating an add in for Microsoft Excel that includes a ribbon tab. On this tab is a button with the following code:
public void setAccounts()
{
foreach (Excel.Worksheet displayWorksheet in Globals.ThisAddIn.Application.Worksheets)
{
displayWorksheet.Range[budget_cell].Value2 = "$" + Convert.ToString(budget);
displayWorksheet.Range[account_cell].Value2 = "$0.00";
displayWorksheet.Range[transaction_cell].Value2 = "Amount";
}
}
The button opens up a separate form where the user specifies budget_cell, account_cell, and transaction_cell. I then pass that data to the above code in SolutionName.ThisAddIn.cs (where SolutionName is the namespace of the solution). Strictly speaking, the code works. However, the data doesn't show up in the cells until the button is pressed a second time. Why is that? Is it because I'm retrieving the data from a different object in the solution?
Also, I've been trying to get this code and the aforementioned form to activate when the add in first starts up.
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
frmStartup startup = new frmStartup();
startup.Show();
setAccounts();
}
I've been at this for a good twelve hours now, and I can't get it to work. What am I missing?
ThisAddIn.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Excel = Microsoft.Office.Interop.Excel;
using Office = Microsoft.Office.Core;
using Microsoft.Office.Tools.Excel;
namespace AccountingAddIn
{
public partial class ThisAddIn
{
public static string budget_cell = "";
public static string account_cell = "";
public static string transaction_cell = "";
public static string date_cell = "";
public static string time_cell = "";
public static string description_cell = "";
public static bool date = false;
public static bool time = false;
public static bool description = false;
public static decimal budget = 0;
List<Account> accounts = new List<Account>();
public void budgetStartUp()
{
frmStartup startup = new frmStartup();
startup.Show();
setAccounts();
}
public void setAccounts()
{
foreach (Excel.Worksheet displayWorksheet in Globals.ThisAddIn.Application.Worksheets)
{
displayWorksheet.Range[budget_cell].Value2 = "$" + Convert.ToString(budget);
displayWorksheet.Range[account_cell].Value2 = "$0.00";
displayWorksheet.Range[transaction_cell].Value2 = "Amount";
if (date == true)
{
displayWorksheet.Range[date_cell].Value2 = "Date";
}
if (time == true)
{
displayWorksheet.Range[time_cell].Value2 = "Time";
}
if (description == true)
{
displayWorksheet.Range[description_cell].Value2 = "Description";
}
Account na = new Account(0, displayWorksheet);
accounts.Add(na);
}
}
protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject()
{
return Globals.Factory.GetRibbonFactory().CreateRibbonManager(
new Microsoft.Office.Tools.Ribbon.IRibbonExtension[] { new MyRibbon() });
}
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
CreateRibbonExtensibilityObject();
budgetStartUp();
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
}
}
}
frmStartup.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace AccountingAddIn
{
public partial class frmStartup : Form
{
public frmStartup()
{
InitializeComponent();
}
private void btnHelp_Click(object sender, EventArgs e)
{
MessageBox.Show("Please enter a starting amount for your budget and " +
"which cells will display the running total for your " +
"accounts." +
"\n\nNote: Leaving the budget blank will" +
" result in a starting budget of $0.00.");
}
private void btnOkay_Click(object sender, EventArgs e)
{
AccountingSeminar.ThisAddIn.budget += Convert.ToDecimal(txtStartingAmount.Text);
AccountingSeminar.ThisAddIn.budget_cell = txtBudget.Text;
AccountingSeminar.ThisAddIn.account_cell = txtAccount.Text;
AccountingSeminar.ThisAddIn.transaction_cell = txtTransaction.Text;
if (chkDate.Checked)
{
AccountingSeminar.ThisAddIn.date_cell = txtDate.Text;
AccountingSeminar.ThisAddIn.date = true;
}
if (chkTime.Checked)
{
AccountingSeminar.ThisAddIn.time_cell = txtTime.Text;
AccountingSeminar.ThisAddIn.time = true;
}
if (chkDescription.Checked)
{
AccountingSeminar.ThisAddIn.description_cell = txtDescription.Text;
AccountingSeminar.ThisAddIn.description = true;
}
Close();
}
}
}