I have a structure like below:
public class BaseClass
{
public string SendError(string Message){
//which method called me
return Message;
}
}
public class TypeAClass : BaseClass
{
public static TypeAClass Instance { get; set;}
public void TestToTest()
{
SendError("Test Message");
}
}
Can I get the method name that calls the SendError() in the SendError method. For example, in this scenario it should give me the name TestToTest()
This is a feature of C# 5:
You can declare a parameter of a function as a caller info:
public string SendError(string Message, [CallerMemberName] string callerName = "")
{
Console.WriteLine(callerName + "called me.");
}
Try this
StackTrace stackTrace = new StackTrace();
String callingMethodName = stackTrace.GetFrame(1).GetMethod().Name;
StackFrame caller = (new System.Diagnostics.StackTrace()).GetFrame(0);
string methodName = caller.GetMethod().Name;
From the answer of the duplicate question:
using System.Diagnostics;
// get call stack
StackTrace stackTrace = new StackTrace();
// get calling method name
Console.WriteLine(stackTrace.GetFrame(1).GetMethod().Name);
Or more brief:
new StackTrace().GetFrame(1).GetMethod().Name
Related
I have an instance of a working command line verb object - and i'd like to generate a command line string that it represents.
using CommandLine;
[Verb("myVerb")]
public class MyClass
{
[Option("myOption")]
public string MyOption { get; set; }
}
public static void Initialise()
{
var instance = new MyClass();
instance.MyOption = "Option Value";
System.Console.WriteLine(BuildCommandLineStringFromInstance(instance));
// Output
// myVerb --myOption="Option Value"
}
Is there anything in the library which provides something similar to the method
string BuildCommandLineStringFromInstance(object)
I am struggling to understand delegates and for that I created a simple example for myself but it doesn't work the way I want it to, here is my example:
my functions:
class Functions
{
public string MyFname(string MyString)
{
return MyString;
}
public string MyLname(string MyString)
{
return MyString;
}
}
delegate:
class DelClass
{
public delegate string StrDelegate(string OutPutString);
public void StringCon(StrDelegate Fname,StrDelegate Lname)
{
Console.WriteLine(Fname + " " + Lname);
}
}
Main:
class Program
{
static void Main(string[] args)
{
DelClass MyDel = new DelClass();
Functions MyTster = new Functions();
DelClass.StrDelegate Name = new DelClass.StrDelegate(MyTster.MyFname);
Name("SomeVariableName");
DelClass.StrDelegate Family = new DelClass.StrDelegate(MyTster.MyLname);
Family("SomeVariableFamilyName");
MyDel.StringCon(Name, Family);
}
}
The problem is Console window doesn't show my passed string instead it shows the undermentioned text:
MyDelegateMethodInMethod.DelClass+StrDelegate MyDelegateMethodInMethod.DelClass+
StrDelegate
And when I try to invoke the passed function in StringCon body like this:
Console.WriteLine(Fname() + " " + Lname();
The compiler complain that "Delegate 'StrDelegate' does not take 0 arguments" but I don't want to pass an argument in StringCon's passed parameters, I want to do it in my Main function, is this even possible with delegates?
A delegate is an object that contains a reference to a method. Invoking the delegate has the effect of executing the method. Your two methods each have a String parameter so to execute either of those methods you pass pass a single String argument. That means that, when you invoke your delegates, they need to pass a single String argument to the method they execute. Where do you think that value is going to come from? The delegate is not going to pluck it out of thin air. You have to pass it to the delegate when you invoke it. In this code:
public void StringCon(StrDelegate Fname,StrDelegate Lname)
{
Console.WriteLine(Fname + " " + Lname);
}
where are you doing that? You're not. You have to provide the arguments to the delegates in order for them to provide them to the methods:
public void StringCon(StrDelegate Fname,StrDelegate Lname)
{
Console.WriteLine(Fname("John") + " " + Lname("Doe"));
}
This is a very poor demonstration though, because your methods don't really do anything useful. How about defining a method does something useful like this:
public string GetFullName(string givenName, string familyName)
{
return givenName + " " + familyName;
}
and a corresponding delegate:
public delegate string FullNameGetter(string givenName, string familyName);
and then invoking it like so:
var fng = new FullNameGetter(GetFullName);
Console.WriteLine(fng("John", "Doe"));
If you do not want to pass a string as input, you should declare the delegates appropriately:
class DelClass
{
public delegate string StrDelegate();
public void StringCon(StrDelegate Fname,StrDelegate Lname)
{
Console.WriteLine(Fname() + " " + Lname());
}
}
From what you wrote, you want to save the string property somewhere - but the delegate is not the place to do it.You can create an object with FName, LName properties:
class Functions
{
public string MyFname() { return MyFnameProperty; }
public string MyLname() { return MyLnameProperty; }
public string MyFnameProperty { get; set; }
public string MyLnameProperty { get; set; }
}
And finally, in Main you will write:
class Program
{
static void Main(string[] args)
{
DelClass MyDel = new DelClass();
Functions MyTster = new Functions();
DelClass.StrDelegate Name = new DelClass.StrDelegate(MyTster.MyFname);
MyTster.MyFnameProperty ="SomeVariableName";
DelClass.StrDelegate Family = new DelClass.StrDelegate(MyTster.MyLname);
MyTster.MyLnameProperty = "SomeVariableFamilyName";
MyDel.StringCon(Name, Family);
}
}
This is not really how you should use delegates, delegates are mainly used as callback functions, or for EventHandlers, or when you like invoke a function.
an example of an EventHandler could be
public delegate void ReportErrorDelegate(object sender, MyCustomEventArgs e);
with a class
public class MyCustomEventArgs : EventArgs
{
// some implementation
public MyCustomEventArgs()
{
}
public MyCustomEventArgs(object argument)
: this()
{
....
}
}
and afterwards you could create an event which is based on your delegate as
public interface IRaiseMyCustomEventArgs
{
event ReportErrorDelegate CustomEventFired;
}
which you could then implement as
public class RaiseMyCustomEventArgs : IRaiseMyCustomEventArgs
{
public event ReportErrorDelegate CustomEventFired;
protected virtual void RaiseCustomEventArgs(object argument)
{
var local = CustomEventFired;
if (local != null) {
local.Invoke(this, new MyCustomEventArgs(argument));
}
}
}
an other option could be to recall a method after you detect that a UI interaction needs to be Invoked, like such
public delegate void SetTextDelegate(TextBox tb, string text);
public void SetText(TextBox tb, string text)
{
if (tb.InvokeRequired)
{
tb.Invoke(new SetTextDelegate(SetText), tb, text);
return;
}
tb.Text = text;
}
that would be called from a thread running inside a windows application (eg)
public void RunThread()
{
// assuming TextBox1 exists on the form
Thread t = new Thread(() => {
SetText(TextBox1, "Hello World");
});
t.Start();
}
Namespace are same of both the class. I need to call xyz() method in WhatsAppSend Class.
This is my method in Form1.cs
public void SendWhatsAppMsg()
{
try
{
WhatsAppSend ws;
ws = new WhatsAppSend(this); //Error Coming on this
ws.xyz(txtNickName.Text.ToString(),
gridSender.Rows[iCurrentChannelNo].Cells[0].Value.ToString(),
gridSender.Rows[iCurrentChannelNo].Cells[1].Value.ToString(),
CreateArrayFrom(i + 1, (i + 1) + iMsgLimitPerNo),
dropWhatsappType.SelectedItem.ToString(),
SendingData(dropWhatsappType.SelectedItem.ToString()),
ext);
}
catch(Exception e)
{
txt.log += e.ToString();
}
}
Method Which I am trying to call in another class WhatsAppSend.cs
namespace WhatsApp_Bulk
{
public class WhatsAppSend
{
public static WhatsAppBulk form1;
public WhatsAppSend(WhatsAppBulk _form1)
{
form1 = _form1;
}
public static String line = "";
public static String command = "";
public static string[] dst;
public static int count_sleep = Convert.ToInt32(form1.txtMsgGap.Text);
public static string WhatsAppType = "";
public static string DataToSend = "";
public static string ext = "";
public void xyz(string nickname, string sender, string password, string[] Datadst, string DataWhatsAppType, string DataDataToSend, string Dataext)
{
dst = Datadst;
WhatsAppType = DataWhatsAppType;
DataToSend = DataDataToSend;
ext = Dataext;
WhatsApp wa = new WhatsApp(sender, password, nickname, true);
}
}
}
Error :
System.TypeInitializationException: The type initializer for 'WhatsApp_Bulk.WhatsAppSend' threw an exception. ---> System.NullReferenceException: Object reference not set to an instance of an object.
at WhatsApp_Bulk.WhatsAppSend..cctor() in d:\WhatsApp Bulk\WhatsApp Bulk\WhatsAppSend.cs:line 32
--- End of inner exception stack trace ---
at WhatsApp_Bulk.WhatsAppSend..ctor(WhatsAppBulk _form1)
at WhatsApp_Bulk.WhatsAppBulk.SendWhatsAppMsg() in d:\WhatsApp Bulk\WhatsApp Bulk\Form1.cs:line 367
Please tell me where I am going wrong
public static int count_sleep = Convert.ToInt32(form1.txtMsgGap.Text);
This line executes on type initialization, when form1 is null.
You set form1 in the instance constructor, which is executed later.
That is the common reason for TypeInitializationException.
UPD:
I can suggest the following
public class WhatsAppSend
{
public WhatsAppBulk form1;
public WhatsAppSend(WhatsAppBulk _form1)
{
form1 = _form1;
count_sleep = Convert.ToInt32(form1.txtMsgGap.Text);
}
public String line = "";
public String command = "";
public string[] dst;
public int count_sleep;
public string WhatsAppType = "";
public string DataToSend = "";
public string ext = "";
public void xyz(string nickname, string sender, string password, string[] Datadst, string DataWhatsAppType, string DataDataToSend, string Dataext)
{
dst = Datadst;
WhatsAppType = DataWhatsAppType;
DataToSend = DataDataToSend;
ext = Dataext;
WhatsApp wa = new WhatsApp(sender, password, nickname, true);
}
}
Please note that public instance fields are still bad design, but i dont know in which context you will use this class, so i leave them public.
Make WhatsAppSend Class Static one and then call, As per my assumption variables declared in that class are the static ones so the class should be having the same Access Modifier.
I've made a method that logs an exception into a folder called Logs and save it in the text file. The format of the text output is like so:
Main thread has thrown an exception # ClassName::MethodName : Exception.ToString();
ClassName::MethodName is a text that should contain which class and which method throws it (while doing the task). How is it possible to pass those arguments? For example, if I have a class named "Test", and I have this method:
public void DoSomething() {
try {
this.Name = "Test";
} catch (Exception e) {
MainForm.Instance.LogException(e);
}
Then if an exception was thrown, the arguments Test::DoSomething will be passed and shown. How is it possible to do it in C#?
You could use Reflection..
public void DoSomething() {
try {
this.Name = "Test";
} catch (Exception e) {
var method = System.Reflection.MethodBase.GetCurrentMethod();
var methodName = method.Name;
var className = method.ReflectedType.Name;
MainForm.Instance.LogException(String.Format("{0} - {1}:{2}", className, methodName, e));
}
The exception has a StackTrace property which gives you as much information as possible as to where the exception was thrown.
You can use the code below:
public static void DoSomething()
{
try
{
throw new InvalidOperationException("Exception");
}
catch (Exception e)
{
StackTrace stackTrace = new StackTrace();
StackFrame stackFrame = stackTrace.GetFrame(0);
Console.WriteLine("Class Name: {0}, Method Name: {1}", stackFrame.GetMethod().Module, stackFrame.GetMethod().Name);
}
}
e.StackTrace.GetFrame(0) will give you the most recent StackFrame.
Given that, e.StackTrace.GetFrame(0).GetMethod() will give you an instance of MethodBase, from this instance, you can get the method name and class
I am passing a custom variable type from one action to another action in a workflow. Here is the definition of the custom object
public class ConfigDatabase
{
public string Name;
public string Host;
public string Port;
public string Instance;
public string User;
public string Password;
}
public class ConfigDatabases
{
public string DatabaseToUse;
public List<ConfigDatabase> DatabaseList;
public ConfigDatabases()
{
DatabaseList = new List<ConfigDatabase>();
}
}
public class ConfigEnvironment
{
public ConfigDatabases EnvironmentConfigDatabase;
public ConfigEnvironment()
{
EnvironmentConfigDatabase = new ConfigDatabases();
}
public ConfigDatabase ReturnDatabaseInfo()
{
ConfigDatabase ConfigDatabaseInfo = new ConfigDatabase();
for (int Count1 = 0; Count1 < EnvironmentConfigDatabase.DatabaseList.Count; Count1++)
{
if (EnvironmentConfigDatabase.DatabaseList[Count1].Name == EnvironmentConfigDatabase.DatabaseToUse)
{
ConfigDatabaseInfo = EnvironmentConfigDatabase.DatabaseList[Count1];
return ConfigDatabaseInfo;
}
}
return ConfigDatabaseInfo;
}
public string GetDatabaseConnectionString()
{
ConfigDatabase DatabaseInfo = ReturnDatabaseInfo();
string ConnectionString = "Data Source=(description=(address=(protocol=tcp)(host=" + DatabaseInfo.Host + ")(port=" + DatabaseInfo.Port + "))(connect_data=(sid=" + DatabaseInfo.Instance + ")));User ID=" + DatabaseInfo.User + ";Password=" + DatabaseInfo.Password + ";";
return ConnectionString;
}
}
During the first step of the action, it will run the following code to load the config data from a file and store in an object (ConfigEnvironment) that is returned in function Execute
public sealed class InitializeEnvironment : CodeActivity<ConfigEnvironment>
{
// Define an activity input argument of type string
public InArgument<string> EnvironmentFileLocation { get; set; }
// If your activity returns a value, derive from CodeActivity<TResult>
// and return the value from the Execute method.
protected override ConfigEnvironment Execute(CodeActivityContext context)
{
// Obtain the runtime value of the Text input argument
string EnvironmentFile = context.GetValue(this.EnvironmentFileLocation);
EnvironmentConfigInitialization EnvironmentInitialize = new EnvironmentConfigInitialization(EnvironmentFile);
ConfigEnvironment EnvironmentDetail = EnvironmentInitialize.LoadData();
return EnvironmentDetail;
}
}
In the subsequent activity in the workflow, I would like to obtain the data stored in this object. However, the following code will have a compile error as EnvironmentDetail object could not find the function GetDatabaseConnectionString.
public sealed class ExecuteSQL : CodeActivity<DataRowCollection>
{
// Define an activity input argument of type string
public InArgument<string> SQLScript { get; set; }
public InArgument<ConfigEnvironment> EnvironmentDetail { get; set; }
// If your activity returns a value, derive from CodeActivity<TResult>
// and return the value from the Execute method.
protected override DataRowCollection Execute(CodeActivityContext context)
{
string connectionString4 = EnvironmentDetail.GetDatabaseConnectionString(); //This create a compile error
}
}
The compile warning is the following
'System.Activities.InArgument' does not contain a definition for 'GetDatabaseConnectionString' and no extension method 'GetDatabaseConnectionString' accepting a first argument of type 'System.Activities.InArgument' could be found (are you missing a using directive or an assembly reference?)
As it turns out, EnvironmentDetail is of Type InArgument (or InArgument<ConfigEnvironment>) but not of Type ConfigEnvironment You need to do a context.Get<ConfigEnvironment>() to get a variable of Type ConfigEnvironment.
Let me know if this solves your problem or if there's something else still amiss ;-)