CallerInfo, get name of variable passed to method (like nameof) - c#

public void Test ()
{
string myString = "hello";
}
public void Method (string text)
{
COnsole.WriteLine ( ... + " : " + text ); // should print "myString : hello"
}
Is it possible to get name of variable passed to a method?
I want to achieve this:
Ensure.NotNull (instnce); // should throw: throw new ArgumentNullException ("instance");
Is it possible? WIth caller info or something similiar?
Without nameof operator?

Problem with reflection is that, once the C# code is compiled, it will no longer have the variable names. The only way to do this is to promote the variable to a closure, however, you wouldn't be able to call it from a function like you are doing because it would output the new variable name in your function. This would work:
using System;
using System.Linq.Expressions;
public class Program
{
public static void Main()
{
string myString = "My Hello string variable";
// Prints "myString : My Hello String Variable
Console.WriteLine("{0} : {1}", GetVariableName(() => myString), myString);
}
public static string GetVariableName<T>(Expression<Func<T>> expr)
{
var body = (MemberExpression)expr.Body;
return body.Member.Name;
}
}
This would NOT work though:
using System;
using System.Linq.Expressions;
public class Program
{
public static void Main()
{
string myString = "test";
// This will print "myVar : test"
Method(myString);
}
public static void Method(string myVar)
{
Console.WriteLine("{0} : {1}", GetVariableName(() => myVar), myVar);
}
public static string GetVariableName<T>(Expression<Func<T>> expr)
{
var body = (MemberExpression)expr.Body;
return body.Member.Name;
}
}

Related

C# How to use lambda expression with dictionary's value which is a method

I'm creating a program which will execute a command after user input.
Some commands I want to implement are: creating, reading a file, getting current working directory etc.
I created a dictionary which will store user input and corresponding command:
public static Dictionary<string, Action<string[]>> Commands { get; set; } = new Dictionary<string, Action<string[]>>()
{
{"pwd", PrintWorkingDirectory },
{"create", CreateFile },
{"print", ReadFile },
};
Unfortunately I have issues with triggering the method:
public void Run()
{
Console.WriteLine("Welcome, type in command.");
string input = null;
do
{
Console.Write("> ");
input = Console.ReadLine();
Execute(input);
} while (input != "exit");
}
public int Execute(string input)
{
if(Commands.Keys.Contains(input))
{
var action = Commands.Values.FirstOrDefault(); //doesn't work, gives '{command} not found'
}
Console.WriteLine($"{input} not found");
return 1;
}
Also I noticed that this solution would not work with method which is not void, but returns something, as for example CreateFile.
public static string CreateFile(string path)
{
Console.WriteLine("Create a file");
string userInput = Console.ReadLine();
try
{
string[] file = userInput.Split(new char[] { ' ' }).Skip(1).ToArray();
string newPath = Path.GetFullPath(Path.Combine(file));
using (FileStream stream = new FileStream(newPath, FileMode.Create, FileAccess.ReadWrite))
{
stream.Close();
}
using (StreamWriter sw = new StreamWriter(newPath))
{
Console.WriteLine("Please type the content.Press Enter to save.");
sw.WriteLine(Console.ReadLine());
sw.Close();
Console.WriteLine("File {0} has been created", newPath);
}
}
catch (Exception)
{
throw;
}
return path;
}
public static void ReadFile(string[] args)
{
Console.WriteLine("Reading file");
string userInput = Console.ReadLine();
string[] file = userInput.Split(new char[] { ' ' }).Skip(1).ToArray();
string newPath = Path.GetFullPath(Path.Combine(file));
string[] lines = File.ReadAllLines(newPath);
foreach (string line in lines)
Console.WriteLine(line);
}
public static void PrintWorkingDirectory(string[] args)
{
var currentDirectory = Directory.GetCurrentDirectory();
Console.WriteLine(currentDirectory);
}
Could somebody advise me how to deal with these issues?
Is it that this dictionary I created does not make much sense at all?
First problem: You're always fetching the first element of the dictionary and are not using the index operator to retrieve the correct value. Therefore change:
if(Commands.Keys.Contains(input))
{
var action = Commands.Values.FirstOrDefault(); //doesn't work, gives '{command} not found'
}
to:
public int Execute(string input)
{
if (Commands.Keys.Contains(input))
{
var action = Commands[input]; //doesn't work, gives '{command} not found'
action?.Invoke(new string[] { });
}
else
{
Console.WriteLine($"{input} not found");
}
return 1;
}
Regarding to your second question about dictionary usage. I think it is ok to use a dictionary to map different commands based on a given key. The alternative would be switch or if constructs, which can be prevented in Object Oriented Programming.
Regarding to your question about string CreateFile(string path). Since C# is strongly typed language your dictionary can only contain objects of type Action<string[]>, so you can't use methods with another signature than that. One solution is to add another dictionary in the form of Dictionary<string,Func<string[], string>. As a result you'll get more and more dictionaries depending on your method signatures. From here on you should think to build to encapsulate your commands in an e.g. CommandInterpreter class, that could offer an API like that:
void Request(string cmdName, string[] cmdParameters);
string GetLastResult();
int GetLastCode();
Update:
Below code shows a possible object oriented solution (I've left out interfaces to make the code more compact):
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
public class Command<T>
{
public string Name { get; }
public T TheCommand { get; }
public Command(string name, T theCommand)
{
Name = name;
TheCommand = theCommand;
}
}
public interface ICommandResult
{
void Ok(Action<ICommandResult> yes, Action<ICommandResult> no);
int Code { get; }
string Description { get; }
}
public abstract class CommandResult : ICommandResult
{
public int Code { get; }
public string Description { get; }
protected CommandResult(int code, string description)
{
Code = code;
Description = description;
}
public abstract void Ok(Action<ICommandResult> yes, Action<ICommandResult> no);
}
public class NullCommandResult : CommandResult
{
public NullCommandResult() : base(-1, "null")
{
}
public override void Ok(Action<ICommandResult> yes, Action<ICommandResult> no) => no?.Invoke(this);
}
public class SuccessCommandResult : CommandResult
{
public SuccessCommandResult(string description) : base(0, description)
{
}
public override void Ok(Action<ICommandResult> yes, Action<ICommandResult> no) => yes?.Invoke(this);
}
public class CommandInterpreter
{
private Dictionary<string, Func<IEnumerable<string>, ICommandResult>> Commands = new Dictionary<string, Func<IEnumerable<string>, ICommandResult>>();
public void RegisterCommand(Command<Func<IEnumerable<string>, ICommandResult>> cmd)
=> Commands.Add(cmd.Name, cmd.TheCommand);
public ICommandResult RunCommand(string name, IEnumerable<string> parameters)
=> Commands.Where(kvp => kvp.Key.Equals(name))
.Select(kvp => kvp.Value)
.DefaultIfEmpty(strArr => new NullCommandResult())
.Single()
.Invoke(parameters);
}
class Program
{
private CommandInterpreter _cmdInterpreter;
private Program()
{
_cmdInterpreter = new CommandInterpreter();
_cmdInterpreter.RegisterCommand(new Command<Func<IEnumerable<string>, ICommandResult>>("pwd", PrintWorkingDirectory));
_cmdInterpreter.RegisterCommand(new Command<Func<IEnumerable<string>, ICommandResult>>("create", CreateFile));
_cmdInterpreter.RegisterCommand(new Command<Func<IEnumerable<string>, ICommandResult>>("print", ReadFile));
}
private static CommandResult ReadFile(IEnumerable<string> arg) => new SuccessCommandResult("File read");
private static CommandResult CreateFile(IEnumerable<string> arg) => new SuccessCommandResult("File xyz created");
private static CommandResult PrintWorkingDirectory(IEnumerable<string> arg) => new SuccessCommandResult("Printed something");
static void Main() => new Program().Run();
private void Run()
{
Console.WriteLine("Welcome, type in command.");
string input;
do
{
Console.Write("> ");
input = Console.ReadLine();
var cmdResult = _cmdInterpreter.RunCommand(input, Enumerable.Empty<string>());
cmdResult.Ok(
r => Console.WriteLine($"Success: {cmdResult.Code}, {cmdResult.Description}"),
r => Console.WriteLine($"FAILED: {cmdResult.Code}, {cmdResult.Description}"));
} while (input != "exit");
}
}
}
Output:
Welcome, type in command.
> pwd
Success: 0, Printed something
> create
Success: 0, File xyz created
> abc
FAILED: -1, null
>
You can just copy the code and play around with it.

Passing Nullable Int using reflection

i am using this code
//Rextester.Program.Main is the entry point for your code. Don't change it.
//Compiler version 4.0.30319.17929 for Microsoft (R) .NET Framework 4.5
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Reflection;
namespace Rextester
{
public class Program
{
public static void Main(string[] args)
{
new Program().DoTest();
}
public void DoTest()
{
var a = LoggingAdvice<asd>.Create(new a());
a.targetMethod("nadeem", 123, null);
}
}
public class LoggingAdvice<T> : DispatchProxy
{
private T _decorated;
protected override object Invoke(MethodInfo targetMethod, object[] args)
{
var result = targetMethod.Invoke(_decorated, args);
var resultTask = result as Task;
return result;
}
public static T Create(T decorated)
{
object proxy = Create<T, LoggingAdvice<T>>();
((LoggingAdvice<T>)proxy).SetParameters(decorated);
return (T)proxy;
}
private void SetParameters(T decorated)
{
if (decorated == null)
{
throw new ArgumentNullException(nameof(decorated));
}
_decorated = decorated;
}
}
public class asd
{
public asd()
{
}
public int targetMethod(string name, int number, int? count)
{
Console.WriteLine(name);
Console.WriteLine(number);
Console.WriteLine(count.HasValue ? count.Value.ToString() : "NULL");
return 1;
}
}
}
the most important thing about it, is this line of code
var result = targetMethod.Invoke(_decorated, args);
the target method has 3 parameters, one of them is nullable integer as the following
public int targetMethod(string name, int number, int? count)
the args that is getting passed to Invoke method has the following values as you can view it in the visual studio debugging mode:
["nadeem", 123, (null)]
the invoke is raising an exception that i cannot convert string to nullable integer.
how i can avoid this type of issue, note that i am not sure which function i am going to be invoked, i would only know it on runtime.

Give an Object a Method in C#

Is it possible to give a C# Object like
public string Name
{
get { return _name; }
set { _name = value; }
}
a Method doing something like:
private void addTextToName(){
_name = _name + " - Test";
}
so that I can call it like
Name.addTextToName();
Because (where I come from) in JavaScript you can do such things with .prototype
Is there any way to do this in C#?
If you are asking can I add a method to a string? then yes. Look at extension methods.
public static string AddTextToName(this string s)
{
return s + " - Test";
}
Use it like this:
"Hello".AddTextToName();
Will return Hello - test.
Yes, there is a way for C# Objects (you used a string there, but though...).
Take a look at the so-called "extension methods" in C# as they are exactly what you need I think.
For further reference, look e.g. here: https://msdn.microsoft.com/en-us/library/vstudio/bb383977%28v=vs.110%29.aspx (the magic is in the this as parameter for the method)
Using the extension method.
class Program
{
static void Main()
{
Example e = new Example();
e.Name = "Hello World";
var x = e.Name;
var y = x.addTextToName();
Console.WriteLine(y);
Console.ReadLine();
}
}
class Example
{
public string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
public static class MyExtensions
{
public static string addTextToName(this string str)
{
return str += " - Test";
}
}

How would you write a method that takes a parameter like [ModelBinder(typeof(GeoPointModelBinder))] GeoPoint location

I was reading an example about the ASP.NET Web API framework, and how you can create a modelbinder to bind parameters during a request.
My question is, how would you write a c# class/method to accept a parameter that looks like:
public HttpResponseMessage Get([ModelBinder(typeof(GeoPointModelBinder))] GeoPoint location)
If you could briefly explain the syntax and the general idea behind it that would be great.
Reference: http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api
using System;
using System.Reflection;
namespace Test081204
{
[AttributeUsage(AttributeTargets.Parameter)]
public class SomeCoolAttribute : System.Attribute
{
public readonly int Val;
public SomeCoolAttribute(int val)
{
Val = val;
}
}
class Test
{
public void Run([SomeCool(123)] string value)
{
// Prints "In Run: test123"
Console.WriteLine("In Run: " + value);
}
}
class Program
{
public static void Main()
{
var parameters = typeof(Test).GetMethod("Run").GetParameters();
var attr = parameters[0].GetCustomAttribute(typeof(SomeCoolAttribute)) as SomeCoolAttribute;
// Prints "123"
Console.WriteLine("In Main: " + attr.Val);
new Test().Run("test" + attr.Val.ToString());
}
}
}

How to pass method result as parameter to base class constructor in C#?

I've trying to achieve something like this:
class App {
static void Main(string[] args) {
System.Console.WriteLine(new Test("abc")); //output: 'abc'
System.Console.ReadLine();
}
}
I can do this passing by an variable:
class Test {
public static string str;
public Test (string input) { str = input; }
public override string ToString() {
return str;
}
}
works fine.
But, my desire is do something as:
class Test {
public static string input;
public Test (out input) { }
public override string ToString() {
return input;
}
}
System.Console.WriteLine(new Test("abc test")); //abc test
Don't works.
How I do this?
Thanks,advanced.
You can't. The variable approach is exactly the correct way, although the variable shouldn't be declared static, and shouldn't be a public field.
class Test {
public string Input {get;set;}
public Test (string input) { Input = input; }
public override string ToString() {
return Input;
}
}
I have an impression that you're not entirely understand what out keyword means. Essentially when you're writing something like void MyMethod(out string var) it means you want to return some value from method, not pass it into method.
For example there's bool Int32.TryParse(string s, out int result). It parses string s, returns if parse was successful and places parsed number to result. Thus, to correctly use out you should have real variable at the calling place. So you can't write Int32.Parse("10", 0) because this method can't assign result of 10 to 0. It needs real variable, like that:
int result;
bool success = Int32.TryParse("10", out result);
So, your desire is somewhat else - it is not in line with language designer's intentions for out :)

Categories

Resources