i am trying to output a log of methods and their actions if taken and results into a "MyAppLog_ListView" the columnsHeaders of the lisftview Are
Record#______MethodName__________MethodsOutput
1 ______GetCurrentTime______success(21:10)
2 ______DoSplitString_______faild(not in right Format)
3......................................etc'...
this helps me debuging my program as it's over 1500 lines of code and atleast for me
it's getting a little too complex , the question is what is the right way to store methods name in a string
public void MyMethod()
{
do stuff
if (comleted) MyAppLog_ListView_AddRecord(string for the methods name, outputSucces)
else if (faild) MyAppLog_ListView_AddRecord(string for the methods name, outputFail)
}
how do i get MyMethod().Name to store in a string ?
ReEdit :
As to SidAhmeds Answer :
public void MyMethodName()
{
do stuff
string Mnam = MethodBase.GetCurrentMethod().Name;
if (comleted) MyAppLog_ListView_AddRecord(Mnam , outputSucces);
else if (faild) MyAppLog_ListView_AddRecord(Mnam , outputFail);
}
Or you could use reflection to do it :
System.Reflection.MethodBase.GetCurrentMethod().Name;
StackTrace st = new StackTrace();
var methodName = st.GetFrame(0).GetMethod().Name;
Related
We are currently working on a logging solution and have implemented an extension method call 'Log'. When writing to the log file, we would ideally like to write the original variable name (rather than the variable name used in the extension method).
What we are currently having to do for this is:
public void DoSomeWork()
{
String testString = "Hey look I'm a string!";
testString.Log("testString value");
}
With the extention method:
public static String Log(this String valueToStore, String name)
{
// The logging code which uses the 'name' parameter
}
The issue here is that it becomes difficult to read on longer lines of code and looks clustered. What would be ideal is this:
public void DoSomeWork()
{
String testString = "Hey look I'm a string!";
testString.Log();
}
With the extension method:
public static String Log(this String valueToStore)
{
// The logging code which is able to retrieve the
// value 'testString' from the 'valueToStore' value
}
Is this at all possible by using Reflection? I'm aware of the nameofoption, but that only returns the string 'valueToStore' when used in the extension method.
Well, short answer is no. The variable names are not guaranteed to persist after compilation in unchanged form. That information would have to be somehow persisted (for example by the use of nameof()). Also, the variable name might not exist ("test".GetVarName()).
The long answer is: yes, possibly, but it's one of the most ridiculous things I've created in my life:
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace Test1
{
class Program
{
static void Main(string[] args)
{
var myVarName = "test";
myVarName.Test();
Console.ReadKey();
}
}
static class Extensions
{
public static void Test(
this string str,
[System.Runtime.CompilerServices.CallerMemberName] string memberName = "",
[System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "",
[System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0
)
{
var relevantLine = File.ReadAllLines(sourceFilePath)[sourceLineNumber-1];
var currMethodName = MethodInfo.GetCurrentMethod().Name;
var callIndex = relevantLine.IndexOf(currMethodName + "()");
var sb = new Stack<char>();
for (var i = callIndex - 2; i >= 0; --i)
{
if (Char.IsLetterOrDigit(relevantLine[i]))
{
sb.Push(relevantLine[i]);
}
}
Console.WriteLine(new String(sb.ToArray()));
}
}
}
C# 10 has CallerArgumentExpressionAttribute that will do just that
public static void PrintNameAndValue(
this object obj,
[System.Runtime.CompilerServices.CallerArgumentExpression("obj")] string callerExp = ""
)
{
Console.WriteLine(callerExp + " = " + obj.ToString());
}
It'll capture the entire expression passed:
public void TestPrintNameAndValue()
{
string mystring = "test";
int myint = 5;
mystring.PrintNameAndValue(); // mystring = test
myint.PrintNameAndValue(); // myint = 5
(myint + 10).PrintNameAndValue(); // myint + 10 = 15
mystring.ToUpper().PrintNameAndValue(); // mystring.ToUpper() = TEST
}
You can use an Expression to achieve that, but performance-wise it may not be the best option:
public static void Log<T>(Expression<Func<T>> expr)
{
var memberExpr = expr.Body as MemberExpression;
if (memberExpr == null)
return;
var varName = memberExpr.Member.Name;
var varData = expr.Compile()();
// actual logging
...
}
Usage:
var test = "Foo";
Log(() => test);
Alternatively, if you're using C# 6.0, it can get a bit better using the nameof operator:
test.Log(nameof(test));
A better solution would be one that is leveraging the compiler abilities (specifically, the "Roslyn" compiler) and provide the member name on compile time.
Not really an answer, more of a pointer, but you could try doing something with your application that you're using(e.g. visual studio) instead of doing it in code. What I mean is make it rewrite everything that looks like [variable].Log(); to [variable].Log([variable])
I am pretty sure that there has to be some weird macro or plugin which does this for you before compiling.
I was very excited to try out the new feature in VS 2012 ultimate that allows you to run whole load tests with coded web tests.
Unfortunatly, I've ran into a bit of a problem. While trying to debug a web test I've generated (and edited afterwards), I keep getting an NullReferenceException on a simple declaration line. I simply cannot wrap my head around why this occurs. Here's the code:
[Priority(0)]
public class CreateSessionCoded : WebTest
{
public string[] SessionID;
public string[] SessionTime;
public string[] CreatedTime;
public CreateSessionCoded()
{
this.Context.Add("Parameter1", "");
this.PreAuthenticate = true;
}
public override IEnumerator<WebTestRequest> GetRequestEnumerator()
{
//string CurrentITR = this.Context.WebTestIteration.ToString();
SessionID[this.Context.WebTestIteration] = Guid.NewGuid().ToString();
SessionTime[this.Context.WebTestIteration] = System.DateTime.UtcNow.ToString();
CreatedTime[this.Context.WebTestIteration] = System.DateTime.Now.ToString();
...
The code goes on, but the part where I get the NRE is at the last two lines where I try to assign values to my SessionTime and CreatedTime parameters.
It doesn't happen when assigning to the SessionID, so it's not about the WebTestIteration in any way. It also happens if I try to assign a different string (any casual string such as, say, "blabla") to the same parameters.
I'd really appreciate any help! Thanks in advance! :)
You define three arrays:
public string[] SessionID;
public string[] SessionTime;
public string[] CreatedTime;
But, they aren't initialized before you attempt to use them.
Basically, you are doing this:
string[] foo;
foo[1] = "bar";
And you need to do this:
string[] foo = new string[10]; // sized appropriately
foo[1] = "bar";
public void FindCityName()
{
string url = "http://maps.google.com/maps/geo?q=39.920794,32.853902&output=json&oe=utf8&sensor=true&key=MYKEY";
var w = new WebClient();
Observable.FromEvent<DownloadStringCompletedEventArgs>(w, "DownloadStringCompleted").Subscribe(r =>
{
var deserialized = JsonConvert.DeserializeObject<RootObject>(r.EventArgs.Result);
string s = deserialized.Placemark[0].AddressDetails.Country.SubAdministrativeArea.Locality.LocalityName;
/// setCity() and City=s produce the same thing
setCity(s);
City = s;
//foreach (var item in deserialized.Placemark)
//{
// //MessageBox.Show(item.AddressDetails.Country.SubAdministrativeArea.Locality.LocalityName);
// City = (string)item.AddressDetails.Country.SubAdministrativeArea.Locality.LocalityName;
//}
//Problem here >>>>>
////MessageBox.Show(City);
});
w.DownloadStringAsync(new Uri(url));
}
Problem:
I am working on a windows phone 7 application and I need to find the "City Name" from GPS coordinates in order to move forward...
I found the code above on the internet and tried it. I can see the city name by using these codes(Message.Box(City) show exactly what I want, the city name). However, this line of code
deserialized.Placemark[0].AddressDetails.Country.SubAdministrativeArea.Locality.LocalityName;
which gives me the city name seems to give a volatile string value.
For example, I created a method which assigns the value of string variable "s" to the string field of my class, name City. If I try to get the City's content after calling FindCityName() method, I see that City's content is not updated.
Again, same thing happens then I call the code line under the comment "Problem here >>>>>" that MessageBox.Show(City) shows nothing new...
Can someone explain me the reason of my problem?
you put this question on my blog as well, but I will answer it here. I feel a bit responsible for putting up the sample code in the first place ;-)
I am going to assume the class containing your code looks like this:
public class MyClass
{
private void MyMethod()
{
FindCityName();
MessageBox.Show(City);
}
private void FindCityName()
{
// Code omitted - see your question
}
private string City;
}
There is nothing volatile about the string. Your problem is asynchronicity. If you look carefully you will see that I use an observable that fires when the DownloadStringCompleted is fired. The code inside Observable.Event is only called when the download is finished but that happens asynchronously. But what I assume you do is call the FindCityName method and then directly trying to access results like I show in the MyMethod method. That's like directly wanting the result after firing the request. The results are not in yet! It's like a web page downloading - it takes a while. You can fix that with a callback, something like this:
public class MyClass
{
private void MyMethod()
{
FindName();
}
public void FindCityName()
{
string url = "http://maps.google.com/maps/geo?q=39.920794,32.853902&output=json&oe=utf8&sensor=true&key=MYKEY";
var w = new WebClient();
Observable.FromEvent<DownloadStringCompletedEventArgs>(w, "DownloadStringCompleted").Subscribe(r =>
{
var deserialized = JsonConvert.DeserializeObject<RootObject>(r.EventArgs.Result);
City = deserialized.Placemark[0].AddressDetails.Country.SubAdministrativeArea.Locality.LocalityName;
DoneDownloading();
});
w.DownloadStringAsync(new Uri(url));
}
private string City;
private void DoneDownloading
{
MessageBox.Show(City);
}
}
Does that help?
I would recommend you to use this Google Map API
http://maps.googleapis.com/maps/api/geocode/json?latlng=39.920794,32.853902&sensor=true
And once you get JSON response in your request. You can parse easily with NEWTONSOFT for wp7
WebClient wc = new WebClient();
var json = (JObject)JsonConvert.DeserializeObject(wc.DownloadString(url));
var locality= json["results"]
.SelectMany(x => x["address_components"])
.FirstOrDefault(t => t["types"].First().ToString() == "locality");
var name = locality!=null ? locality["long_name"].ToString() : "";
I been having trouble trying to figure this out. When I think I have it I get told no. Here is a picture of it.
I am working on the save button. Now after the user adds the first name, last name and job title they can save it. If a user loads the file and it comes up in the listbox, that person should be able to click on the name and then hit the edit button and they should be able to edit it. I have code, but I did get inform it looked wackey and the string should have the first name, last name and job title.
It is getting me really confused as I am learning C#. I know how to use savefiledialog but I am not allowed to use it on this one. Here is what I am suppose to be doing:
When the user clicks the “Save” button, write the selected record to
the file specified in txtFilePath (absolute path not relative) without
truncating the values currently inside.
I am still working on my code since I got told that it will be better file writes records in a group of three strings. But this is the code I have right now.
private void Save_Click(object sender, EventArgs e)
{
string path = txtFilePath.Text;
if (File.Exists(path))
{
using (StreamWriter sw = File.CreateText(path))
{
foreach (Employee employee in employeeList.Items)
sw.WriteLine(employee);
}
}
else
try
{
StreamWriter sw = File.AppendText(path);
foreach (var item in employeeList.Items)
sw.WriteLine(item.ToString());
}
catch
{
MessageBox.Show("Please enter something in");
}
Now I can not use save or open file dialog. The user should be able to open any file on the C,E,F drive or where it is. I was also told it should be obj.Also the program should handle and exceptions that arise.
I know this might be a noobie question but my mind is stuck as I am still learning how to code with C#. Now I have been searching and reading. But I am not finding something to help me understand how to have all this into 1 code. If someone might be able to help or even point to a better web site I would appreciate it.
There are many, many ways to store data in a file. This code demonstrates 4 methods that are pretty easy to use. But the point is that you should probably be splitting up your data into separate pieces rather than storing them as one long string.
public class MyPublicData
{
public int id;
public string value;
}
[Serializable()]
class MyEncapsulatedData
{
private DateTime created;
private int length;
public MyEncapsulatedData(int length)
{
created = DateTime.Now;
this.length = length;
}
public DateTime ExpirationDate
{
get { return created.AddDays(length); }
}
}
class Program
{
static void Main(string[] args)
{
string testpath = System.IO.Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "TestFile");
// Method 1: Automatic XML serialization
// Requires that the type being serialized and all its serializable members are public
System.Xml.Serialization.XmlSerializer xs =
new System.Xml.Serialization.XmlSerializer(typeof(MyPublicData));
MyPublicData o1 = new MyPublicData() {id = 3141, value = "a test object"};
MyEncapsulatedData o2 = new MyEncapsulatedData(7);
using (System.IO.StreamWriter w = new System.IO.StreamWriter(testpath + ".xml"))
{
xs.Serialize(w, o1);
}
// Method 2: Manual XML serialization
System.Xml.XmlWriter xw = System.Xml.XmlWriter.Create(testpath + "1.xml");
xw.WriteStartElement("MyPublicData");
xw.WriteStartAttribute("id");
xw.WriteValue(o1.id);
xw.WriteEndAttribute();
xw.WriteAttributeString("value", o1.value);
xw.WriteEndElement();
xw.Close();
// Method 3: Automatic binary serialization
// Requires that the type being serialized be marked with the "Serializable" attribute
using (System.IO.FileStream f = new System.IO.FileStream(testpath + ".bin", System.IO.FileMode.Create))
{
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf =
new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
bf.Serialize(f, o2);
}
// Demonstrate how automatic binary deserialization works
// and prove that it handles objects with private members
using (System.IO.FileStream f = new System.IO.FileStream(testpath + ".bin", System.IO.FileMode.Open))
{
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf =
new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
MyEncapsulatedData o3 = (MyEncapsulatedData)bf.Deserialize(f);
Console.WriteLine(o3.ExpirationDate.ToString());
}
// Method 4: Manual binary serialization
using (System.IO.FileStream f = new System.IO.FileStream(testpath + "1.bin", System.IO.FileMode.Create))
{
using (System.IO.BinaryWriter w = new System.IO.BinaryWriter(f))
{
w.Write(o1.id);
w.Write(o1.value);
}
}
// Demonstrate how manual binary deserialization works
using (System.IO.FileStream f = new System.IO.FileStream(testpath + "1.bin", System.IO.FileMode.Open))
{
using (System.IO.BinaryReader r = new System.IO.BinaryReader(f))
{
MyPublicData o4 = new MyPublicData() { id = r.ReadInt32(), value = r.ReadString() };
Console.WriteLine("{0}: {1}", o4.id, o4.value);
}
}
}
}
As you are writing the employee objects with WriteLine, the underlying ToString() is being invoked. What you have to do first is to customize that ToString() methods to fit your needs, in this way:
public class Employee
{
public string FirstName;
public string LastName;
public string JobTitle;
// all other declarations here
...........
// Override ToString()
public override string ToString()
{
return string.Format("'{0}', '{1}', '{2}'", this.FirstName, this.LastName, this.JobTitle);
}
}
This way, your writing code still keeps clean and readable.
By the way, there is not a reverse equivalent of ToSTring, but to follow .Net standards, I suggest you to implement an Employee's method like:
public static Employee Parse(string)
{
// your code here, return a new Employee object
}
You have to determine a way of saving that suits your needs. A simple way to store this info could be CSV:
"Firstname1","Lastname 1", "Jobtitle1"
" Firstname2", "Lastname2","Jobtitle2 "
As you can see, data won't be truncated, since the delimiter " is used to determine string boundaries.
As shown in this question, using CsvHelper might be an option. But given this is homework and the constraints therein, you might have to create this method yourself. You could put this in Employee (or make it override ToString()) that does something along those lines:
public String GetAsCSV(String firstName, String lastName, String jobTitle)
{
return String.Format("\"{0}\",\"{1}\",\"{2}\"", firstName, lastName, jobTitle);
}
I'll leave the way how to read the data back in as an exercise to you. ;-)
Thanks all for the suggestion made for my earlier query regarding to the getlist and copy.
I have only one issue here
String realname= "test" //am getting this value from Db,so is this anyway i can use like that rather than
string realname="test"//i know i can do like string realname=""+Dbvalue+"";
Am just wondering why it doesn't return anyvalue if don't use "*" ?
class Program
{
static void Main(string[] args)
{
var getfiles = new fileshare.Program();
string realname = "*test*";
foreach (var file in getfiles.GetFileList(realname))
{getfiles.copytolocal(file.FullName); }
}
private FileInfo[] GetFileList(string pattern)
{
var di = new DirectoryInfo(#"\\testserv01\dev");
return di.GetFiles(pattern);
}
private void copytolocal(string filename)
{
string nameonly = Path.GetFileName(filename);
File.Copy(filename,Path.Combine(#"c:\",nameonly));
}
}
Thanks in Advance.
I know this is a bit glib but really you need to start looking at the documentation of the functionality you are using: http://msdn.microsoft.com/en-us/library/8he88b63.aspx
that said the reason is that * is a wildcard - if you use "test" then you will only retrieve exact matches for "test".
the link above has some more examples.