Obtaining name of property without passing it in via reflection? - c#

I'm trying to do something like this:
public static class Validate
{
public static void AgainstNull(string str)
{
if (String.IsNullOrWhiteSpace(str))
{
// how do I know the property name in the calling code?
throw new ArgumentNullException("property name from caller");
}
}
}
So that I can use a pattern similar to this in my code base:
public void Foo(string bar)
{
Validate.AgainstNull(bar);
// other processing here
}
How do I know the name of the property which was passed in from the calling code inside of my validate method?

As Chris Sinclair mentioned, you can use LINQ expression, here is an example of such code:
public static class Validate
{
public static void AgainstNull(System.Linq.Expressions.Expression<Func<string>> expr)
{
var str = expr.Compile().Invoke();
if (str == null)
{
string name = (expr.Body as System.Linq.Expressions.MemberExpression).Member.Name;
throw new ArgumentNullException(name);
}
}
}

It's not directly possible, but there's a technique/hack that allows the retrieval of the parameter names by making them members of an anonymous type.
Based on your example, this is not a fit. It introduces unnecessary ambiguity and requires weakly typed method signature(s). It's also measurably slower than just passing the string name of the parameter in question.
Again, don't use this for the stated purpose.
Code
void Main()
{
Foo( "hello", "world", 123, false );
}
private static void Foo( string bar, string baz, int abc, bool xyz )
{
Evaluate( new { bar, baz, abc, xyz } );
}
private static void Evaluate( object o )
{
var properties = System.ComponentModel.TypeDescriptor.GetProperties( o );
foreach( System.ComponentModel.PropertyDescriptor propertyDescriptor in properties )
{
var value = propertyDescriptor.GetValue( o );
Console.WriteLine( "Name: {0}, Value: {1}", propertyDescriptor.Name, value );
}
}
Output
Name: bar, Value: hello
Name: baz, Value: world
Name: abc, Value: 123
Name: xyz, Value: False
When might this pattern be appropriate?
It's worth noting that the ASP.Net MVC framework uses anonymous types extensively as a syntactic shortcut. The ComponentModel code comes straight from RouteValueDictionary.

Simple answer: you can't.
There are attributes in newer version of .NET that I thought would be helpful, but those don't look like they'd do the trick either.

You can use Expression Tree to get names of parameters
public static class Validate
{
public static void AgainstNull(string str)
{
if (String.IsNullOrWhiteSpace(str))
{
var parametersNames = GetParameterNames(() => AgainstNull(str));
throw new ArgumentNullException(parametersNames[0]);
}
}
private static string[] GetParameterNames(Expression<Action> expression)
{
var methodInfo = ((MethodCallExpression)expression.Body).Method;
var names = methodInfo.GetParameters().Select(p => p.Name);
return names.ToArray();
}
}
[Fact]
public void AgainstNullTest()
{
var ex = Assert.Throws<ArgumentNullException>(() => Validate.AgainstNull(string.Empty));
Assert.True(ex.Message.EndsWith("str"));
}

Related

Passsing a value to a method using a custom attribute

I'm trying to understand how can I use custom attributes to call method passing a parameters
[ExecuteMe("hello", "reflection")]
public void M3(string s1, string s2)
{
Console.WriteLine("M3 s1={0} s2={1}", s1, s2);
}
I'm trying to call this method using this code:
static void Main(string[] args)
{
var assembly= Assembly.LoadFrom("MyLibrary.dll");
foreach (var type in assembly.GetTypes())
{
object act = Activator.CreateInstance(type);
var methodInfos = type.GetMethods().Where(m => m.GetCustomAttributes(typeof(ExecuteMe)).Any());
foreach (var mInfo in methodInfos)
{
//Console.WriteLine(mInfo.Name);
var argument = mInfo.GetParameters();
foreach (var a in argument)
{
Console.WriteLine(a);
// a.RawDefaultValue;
mInfo.Invoke(act, new object[]{a});
}
}
if (type.IsClass)
Console.WriteLine(type.FullName);
}
Console.ReadLine();
}
It doesn't work because "a" is a ParameterInfo and invoke want a Object[].
What am I doing wrong and how do I get those values?
this is my attribute:
public class ExecuteMe : Attribute
{
public object[] args;
public ExecuteMe(params object[] _args)
{
this.args = _args;
}
}`
I've rewritten it a little. You never actually accessed the arguments you gave to your attribute.
namespace StackOverflow
{
using System;
using System.Reflection;
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = true)]
public class ExecuteMe : Attribute
{
public object[] Arguments { get; }
public ExecuteMe(params object[] args)
{
this.Arguments = args;
}
}
public class TestSubject
{
[ExecuteMe(5, "Hello")]
[ExecuteMe(7, "World")]
public int Function(int i, string s)
{
Console.WriteLine("Executing TestSubject.Function with parameters {0} and {1}", i, s);
return 42;
}
}
internal static class Program
{
internal static void Main(string[] args)
{
// This could come from another dll, for example
// var assembly = Assembly.LoadFrom("MyLibrary.dll").GetTypes();
var availableTypes = Assembly.GetExecutingAssembly().ExportedTypes;
foreach (var type in availableTypes)
{
foreach (var method in type.GetMethods())
{
foreach (var attribute in method.GetCustomAttributes<ExecuteMe>())
{
var instance = Activator.CreateInstance(type);
method.Invoke(instance, attribute.Arguments);
}
}
}
Console.ReadLine();
}
}
}
This should yield:
To make sure I understand what you're trying to do, if a method has an ExecuteMe attribute, you want to call the method, passing the arguments from the attribute to the method?
I'm going to assume that this is just for experimentation and you already realize that this doesn't guarantee whether the number or type of arguments supplied to the attribute will match the number and type of arguments the method requires. The attribute takes an unlimited number of objects, while the method requires two strings.
The issue that you're seeing is that you're looking at .GetParameters which doesn't tell you anything about the values coming from the attribute. It just describes what the parameters of the method are.
What you need is to get the args property from the attribute and pass those values when you invoke the method.
Just for the sake of illustration I'm going to use a method where the signatures match.
public class ClassWithMethod
{
[ExecuteMe("hello", "reflection")]
public void M3(params object[] args)
{
var strings = args.Where(arg => arg != null).Select(arg => arg.ToString());
Console.WriteLine(string.Join(", ", strings));
}
// Just to verify that we're only invoking methods with the attribute.
public void MethodWithoutAttribute() { }
}
...and in the console app I'm going to read types from the executing assembly just for convenience.
I rearranged a few things but you'll see what's going on:
static void Main(string[] args)
{
var assembly = Assembly.GetExecutingAssembly();
foreach (var type in assembly.GetTypes())
{
var methodInfos = type.GetMethods();
// looking at all the methods, not yet narrowing it down to those
// with the attribute.
foreach (var mInfo in methodInfos)
{
// We don't just want to know if it has the attribute.
// We need to get the attribute.
var executeMeParameter = mInfo.GetCustomAttribute<ExecuteMe>();
// If it's null the method doesn't have the attribute.
// Ignore this method.
if (executeMeParameter == null) continue;
// We don't need to create the instance until we know that we're going
// to invoke the method.
object act = Activator.CreateInstance(type);
// Pass the args property of the attribute (an array of objects)
// as the argument list for the method.
mInfo.Invoke(act, new object[]{executeMeParameter.args});
}
if (type.IsClass)
Console.WriteLine(type.FullName);
}
Console.ReadLine();
}
In this case we're just passing all of the arguments from the attribute. This is the part where it's a little messy. What if args had three string values but the method had a single int parameter?
This part is a little weird. I had to do this because of the params keyword.
mInfo.Invoke(act, new object[]{executeMeParameter.args});
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Another reason why I'm assuming that this is just for experimentation is that if you wanted to use an attribute to determine which method to run and to pass in hard-coded parameters (which itself is something I can't see doing), this would be much easier:
[ExecuteMe]
public void CallM3()
{
M3("Hello", "reflection");
}
public void M3(params object[] args)
{
var strings = args.Where(arg => arg != null).Select(arg => arg.ToString());
Console.WriteLine(string.Join(", ", strings));
}
...and the attribute has no arguments:
public class ExecuteMe : Attribute
{
}
The difference now is that everything is strongly typed and compiles. You don't have to worry about whether the parameters will match up at runtime.

Determine if MethodInfo represents a lambda expression

How does one determine if a MethodInfo represents the metadata for a lambda expression?
I think you are talking about anonymous methods.So, you can write an extension method for that and check whether the name of the method contains any invalid chars.Because the compiler generated methods contain invalid chars, you can use that feature to determine whether the method is anonymous or not:
public static bool IsAnonymous(this MethodInfo method)
{
var invalidChars = new[] {'<', '>'};
return method.Name.Any(invalidChars.Contains);
}
Test:
Func<int> f = () => 23;
Console.Write(f.Method.IsAnonymous()); // true
More elegant way would be validating the method name using IsValidLanguageIndependentIdentifier method, like this (method from this answer):
public static bool IsAnonymous(this MethodInfo method)
{
return !CodeGenerator.IsValidLanguageIndependentIdentifier(method.Name);
}
Remember in order to access IsValidLanguageIndependentIdentifier method you need to include the System.CodeDom.Compiler namespace.
The following code can do the trick. It is a bit long compared to the accepted answer, but alas the accepted answer does not make a proper distinction between lambdas and inner methods, which both get name mangled by the compiler. Hence the following provide two methods: IsAnonymous and IsInner.
By the way, the code should work under Mono as well (names seem to be mangled the same way but with a different magic tag under the hood).
public static class MethodInfoUtil
{
static readonly Regex MagicTagPattern = new Regex(">([a-zA-Z]+)__");
static readonly string AnonymousMagicTag;
static readonly string InnerMagicTag;
public static bool IsAnonymous(this MethodInfo mi)
{
return mi.Name.Contains(AnonymousMagicTag);
}
public static bool IsInner(this MethodInfo mi)
{
return mi.Name.Contains(InnerMagicTag);
}
public static string GetNameMagicTag(this MethodInfo mi, bool noThrow = false)
{
var match = MagicTagPattern.Match(mi.Name);
if (match.Success && match.Value is string value && !match.NextMatch().Success)
return value;
else if (noThrow)
return null;
else
throw new ArgumentException($"Cant find magic tag of {mi}");
}
// static constructor: initialize the magic tags
static MethodInfoUtil()
{
void Inner() { };
Action inner = Inner;
Action anonymous = () => { };
InnerMagicTag = GetNameMagicTag(inner.Method);
AnonymousMagicTag = GetNameMagicTag(anonymous.Method);
CheckThatItWorks();
}
[Conditional("DEBUG")]
static void CheckThatItWorks()
{
// Static mathods are neither anonymous nor inner
Debug.Assert(!((Func<int, int>)Math.Abs).Method.IsAnonymous());
Debug.Assert(!((Func<int, int>)Math.Abs).Method.IsInner());
// Instance methods are neither anonymous nor inner
Debug.Assert(!((Func<string, bool>)"".StartsWith).Method.IsAnonymous());
Debug.Assert(!((Func<string, bool>)"".StartsWith).Method.IsInner());
// Lambda
Action anonymous1 = () => { };
Debug.Assert(anonymous1.Method.IsAnonymous());
Debug.Assert(!anonymous1.Method.IsInner());
// Anonymous delegates
Action anonymous2 = delegate(){ };
Debug.Assert(anonymous2.Method.IsAnonymous());
// Sublambdas
Action anonymous3 = new Func<Func<Action>>(() => () => () => { })()();
Debug.Assert(anonymous3.Method.IsAnonymous());
void Inner() { }
Action inner1 = Inner;
Debug.Assert(inner1.Method.IsInner());
Debug.Assert(!inner1.Method.IsAnonymous());
// Deep inner methods have same tag as inner
Action Imbricated()
{
void Inside() { };
return Inside;
}
Action inner2 = Imbricated();
Debug.Assert(inner2.Method.IsInner());
}
}

Setting a ref to a member field in C#

I'd like to assign a reference to a member field. But I obviously do not understand this part of C# very well, because I failed :-) So, here's my code:
public class End {
public string parameter;
public End(ref string parameter) {
this.parameter = parameter;
this.Init();
Console.WriteLine("Inside: {0}", parameter);
}
public void Init() {
this.parameter = "success";
}
}
class MainClass {
public static void Main(string[] args) {
string s = "failed";
End e = new End(ref s);
Console.WriteLine("After: {0}", s);
}
}
Output is:
Inside: failed
After: failed
How do I get "success" on the console?
Thanks in advance,
dijxtra
As others have pointed out, you cannot store a reference to a variable in a field in C#, or indeed, any CLR language.
Of course you can capture a reference to a class instance that contains a variable easily enough:
sealed class MyRef<T>
{
public T Value { get; set; }
}
public class End
{
public MyRef<string> parameter;
public End(MyRef<string> parameter)
{
this.parameter = parameter;
this.Init();
Console.WriteLine("Inside: {0}", parameter.Value);
}
public void Init()
{
this.parameter.Value = "success";
}
}
class MainClass
{
public static void Main()
{
MyRef<string> s = new MyRef<string>();
s.Value = "failed";
End e = new End(s);
Console.WriteLine("After: {0}", s.Value);
}
}
Easy peasy.
There are really two issues here.
One, as the other posters have said, you can't strictly do what you're looking to do (as you may be able to with C and the like). However - the behavior and intent are still readily workable in C# - you just have to do it the C# way.
The other issue is your unfortunate attempt to try and use strings - which are, as one of the other posters mentioned - immutable - and by definition get copied around.
So, having said that, your code can easily be converted to this, which I think does do what you want:
public class End
{
public StringBuilder parameter;
public End(StringBuilder parameter)
{
this.parameter = parameter;
this.Init();
Console.WriteLine("Inside: {0}", parameter);
}
public void Init()
{
this.parameter.Clear();
this.parameter.Append("success");
}
}
class MainClass
{
public static void Main(string[] args)
{
StringBuilder s = new StringBuilder("failed");
End e = new End(s);
Console.WriteLine("After: {0}", s);
}
}
It sounds like what you're trying to do here is make a field a reference to another storage location. Essentially having a ref field in the same way you have a ref parameter. This is not possible in C#.
One of the main issues with doing this is that in order to be verifiable the CLR (and C#) must be able to prove the object containing the field won't live longer than the location it points to. This is typically impossible as objects live on the heap and a ref can easily point into the stack. These two places have very different lifetime semantics (heap typically being longer than the stack) and hence a ref between can't be proven to be valid.
If you don't want to introduce another class like MyRef or StringBuilder because your string is already a property in an existing class you can use a Func and Action to achieve the result you are looking for.
public class End {
private readonly Func<string> getter;
private readonly Action<string> setter;
public End(Func<string> getter, Action<string> setter) {
this.getter = getter;
this.setter = setter;
this.Init();
Console.WriteLine("Inside: {0}", getter());
}
public void Init() {
setter("success");
}
}
class MainClass
{
public static void Main(string[] args)
{
string s = "failed";
End e = new End(() => s, (x) => {s = x; });
Console.WriteLine("After: {0}", s);
}
}
And if you want to simplify the calling side further (at the expense of some run-time) you can use a method like the one below to turn (some) getters into setters.
/// <summary>
/// Convert a lambda expression for a getter into a setter
/// </summary>
public static Action<T, U> GetSetter<T,U>(Expression<Func<T, U>> expression)
{
var memberExpression = (MemberExpression)expression.Body;
var property = (PropertyInfo)memberExpression.Member;
var setMethod = property.GetSetMethod();
var parameterT = Expression.Parameter(typeof(T), "x");
var parameterU = Expression.Parameter(typeof(U), "y");
var newExpression =
Expression.Lambda<Action<T, U>>(
Expression.Call(parameterT, setMethod, parameterU),
parameterT,
parameterU
);
return newExpression.Compile();
}
At this line:
this.parameter = parameter;
...you copy the method parameter to the class member parameter. Then, in Init() you are assigning the value "success", again, to the class member parameter. In your Console.Writeline, then, you are writing the value of the method parameter, "failed", because you never actually modify the method parameter.
What you are trying to do - the way you are trying to do it - is not possible, I believe in C#. I wouldn't try passing a string with the ref modifier.
As answered by JaredPar, you can't.
But the problem is partly that string is immutable. Change your parameter to be of class Basket { public string status; } and your code would basically work. No need for the ref keyword, just change parameter.status.
And the other option is of course Console.WriteLine("After: {0}", e.parameter);. Do wrap parameter in a (write-only) property.

Class member as a first-class object

I was wondering if there is something in c# to be able to pass a member of a class to another function that will use this member to get a value. So get a value of a field determined only which one at runtime. Something like in other languages (PHP at least I think) that you can do
a.b = "something"
but also
a["b"] = "something";
edit: actually not so good an example since a string is used, sorry
For clarity an example of what I'd like to be able to do:
class A
{
int x;
int y;
}
void somethingsomething<T>(T class, SomeMagicFieldClass f)
{
dosomethingwith(somemethodthatgivesmethevalueoffield(class, f));
}
Where then I can call the method like this:
A a = new A();
somethingsomething(a, A.x); //hypothetical notation
somethingsomething(a, A.y);
I now have something similar where I do:
somethingsomething(a, "x");
somethingsomething(a, "y");
I then go find the field using introspection API (also trying GetProperty)
MemberInfo memberInfo = item.GetType().GetField(fieldName);
This works but the disadvantage is that the fields passed as a string won't get updated when "refactoring" fieldnames in visual studio, so I was thinking maybe there exists something like this in c# that would get refactored automatically when changing field names?
Thanks a lot for reading this boring question
Your example looks a lot like a LINQ key selector, in that form it would look like:
A a = new A();
somethingsomething(a, p => p.x);
You can do some nice refactor-friendly things with LINQ Expressions. Here is a snippet of utilty code I used for such occasions. It allows you to get the Name, Type and Value of a property (it won't work with fields without modifications). There's also a setter for the value.
public static void Main(string[] args) {
var test = new { Test1 = 42, Test2 = "123", Test3 = 3.14195 };
somethingSomething(test, t => t.Test1);
somethingSomething(test, t => t.Test2);
somethingSomething(test, t => t.Test3);
}
static void somethingSomething<TObj,TProperty>(TObj obj, Expression<Func<TObj,TProperty>> expr) {
var accessor = GetMemberAccessor(expr, obj);
String name = accessor.Name;
TProperty value = accessor.Value;
String typeName = accessor.Type.Name;
Console.WriteLine("{0} = {1} ({2})", name, value, typeName);
}
The output of that would be:
Test1 = 42 (Int32)
Test2 = 123 (String)
Test3 = 3.14195 (Double)
To make this work, I used the following helper function and class:
public static MemberAccessor<TReturn> GetMemberAccessor<TObj,TReturn>(Expression<Func<TObj, TReturn>> expr, TObj tar) {
var body = expr.Body;
MemberExpression memberExpression = null;
if (body is UnaryExpression) {
var ue = (UnaryExpression)body;
memberExpression = (MemberExpression)ue.Operand;
} else if (body is MemberExpression)
memberExpression = (MemberExpression)body;
else
throw new NotImplementedException("can't get MemberExpression");
String name = memberExpression.Member.Name;
return new MemberAccessor<TReturn>(tar, name);
}
public class MemberAccessor<T> {
private readonly PropertyDescriptor propertyDesc;
private readonly Object target;
public MemberAccessor(Object target, String propertyName) {
this.target = target;
this.propertyDesc = TypeDescriptor.GetProperties(target)[propertyName];
}
public String Name {
get { return propertyDesc.Name; }
}
public Type Type {
get { return propertyDesc.PropertyType; }
}
public T Value {
get { return (T)Convert.ChangeType(propertyDesc.GetValue(target), typeof(T)); }
set { propertyDesc.SetValue(target, value); }
}
}
Mr. Plunkett is correct; a dynamic type will do the job. Luckily, the .NET 4 team included a handy object called the ExpandoObject that solves that for you.
You asked how to
pass a member of a class to another
function that will use this member to
get a value
You can usedelegates for this
class A
{
public string aField;
public string aProperty{get{return "someval";}}
public string aMemberFunction(){return "someval";}
}
void get_a_value(Func<string> func)
{
string theValue = func();
}
// use it:
A a = new A();
get_a_value( () => a.aField);
get_a_value( () => a.aProperty);
get_a_value( () => a.aMemberFunction());
What you don't get this way, of course, is a separation of parameters for the memberfunction and the object you are passing.

o => o.MethodWithParameters | is it possible to use a method in a lambda without () and parameters

i have a method that takes as a parameter an expression because I need the method string name, and I don't care about the parameters of that method, is it possible to do that ?
I don't think that there is. You can however make a generic helper method that you can put in place of the parameters:
public T Any<T>(){
return default(T);
}
and you can call it like so:
YourMethod((YourClass yc) => yc.SomeMethod(Any<SomeClass>(), Any<SomeOtherClass>());
Yes, it's possible. Here is a concept proof test.
private static T RunExpression<T>(Expression<Func<T>> run )
{
var callExpression = (MethodCallExpression) run.Body;
var procedureName = callExpression.Method.Name;
Trace.WriteLine(procedureName);
foreach (var argument in callExpression.Arguments)
{
Trace.WriteLine(argument);
}
Trace.WriteLine(callExpression.Arguments.Count);
// Some really wicked stuff to assign out parameter
// Just for demonstration purposes
var outMember = (MemberExpression)callExpression.Arguments[1];
var e = Expression.Lambda<Func<object>>(outMember.Expression);
var o = e.Compile().Invoke();
var prop = o.GetType().GetField("s");
prop.SetValue(o, "Hello from magic method call!");
Trace.WriteLine(run.Body);
return default(T);
}
[TestMethod]
public void TestExpressionInvocation()
{
var action = new MyActionObject();
string s = null;
RunExpression(() => action.Create(1, out s));
Assert.AreEqual("Hello from magic method call!", s);
}
The easiest way to do this doesn't even use expression trees:
void Main()
{
Console.Out.WriteLine(GetNameOfMethod(new Action(Main)));
Console.Out.WriteLine(GetNameOfMethod(new Func<Delegate, string>(GetNameOfMethod)));
Console.Out.WriteLine(GetNameOfMethod(new Func<int, short, long>(AddNumber)));
Console.Out.WriteLine(GetNameOfMethod(new Action<int, short>(SwallowNumber)));
}
string GetNameOfMethod(Delegate d){
return d.Method.Name;
}
long AddNumber(int x, short y){ return x+y; }
void SwallowNumber(int x, short y){}
yields:
Main
GetNameOfMethod
AddNumber
SwallowNumber
I use this to build a BDD framework on http://storyq.codeplex.com.
Click here to see the file where I do this.
You can use this method without parameters but parentheses (even empty) are required, because without them you tell the compiler to access a property of that name.
You can use something like:
(credits go to klausbyskov)
But it's less verbose.
Also you will need to provide overloads for various argument lists.
[TestClass]
public class TestExpressions
{
public class MyClass
{
public bool MyMethod(string arg)
{
throw new NotImplementedException();
}
}
private static string UseExpression<T, Ta1>(Expression<Action<T,Ta1>> run)
{
return ((MethodCallExpression)run.Body).Method.Name;
}
[TestMethod]
public void TestExpressionParser()
{
Assert.AreEqual("MyMethod",
UseExpression<MyClass,string>((c,fakeString) => c.MyMethod(fakeString)));
}
}

Categories