Get property name C# - c#

I have a class :
class Sample
{
...
}
and define a property like this:
Sample sampleParam =new Sample(...);
and have a function :
private void Func(Sample s)
{}
and use it like:
Func(sampleParam);
can I get the 's' name in the function? I mean can I get "sampleParam"(the name of param)?
It sounds odd; but I need the name of the passed param.
and sorry for this type of asking; I just wanted to ask my question as simple as possible

public string GetParamName(System.Reflection.MethodInfo method,int index)
{
string strParameterName = string.Empty;
if (method != null && method.GetParameters().Length > index)
strParameterName = method.GetParameters()[index].Name;
return retVal;
}
Yes there is a way to achieve this through Reflection...

You should never reference variable or property names from called methods - it's bad manners and bad design (mostly the latter).
There is nameof operator in C# 6.0, but it wasn't designed for this.
You could use expression trees, which would slightly change your syntax. If sampleParam is not a property but a variable, you can't really access it, because compiler does not store any references to that name in generated dll file.

This isn't exactly what you're asking for, but is perhaps closer to what you want, but you could take a look at System.Environment.StackTrace.

I think it is not possible to get the name for a variable which value is passed to a method. But there is the compiler service CallerMemberNameAttribute which copies the name of the caller method (here the get accessor of our property Name) to the calling method if not specified:
class Person {
static void Main(string[] args) {
Person bart = new Person();
bart.Name = "Bart";
Console.ReadKey();
}
private string _name;
public string Name {
get {
return _name;
} set {
_name = value;
PropertyChanged(); //no need to fill in `Name` here! :)
}
}
//automatically copy caller's name to `propertyName`, at compile time
private void PropertyChanged([CallerMemberName] string propertyName = "") {
object propertyValue = this.GetType().GetProperty(propertyName).GetValue(this);
Console.WriteLine("Property '" + propertyName + "' changed the value to '" + propertyValue + "'");
}
}
Prints:
Property 'Name' changed the value to 'Bart'

If you mean can you get the name 'sampleParam' from INSIDE func? The the answer is no. There is nameof() in C#6.0 but 'sampleParam' inside not in scope inside the func. The variable s (of type Sample) is crated and assigned a ref to sampleParam.
You can get the name "s" inside Func.
You can get the name "sampleParam" in the calling class (outside Func).
Example (available on dotnetfiddle)
using System;
public class Program
{
public static Sample sampleParam {get; set;} =new Sample();
public static void Main()
{
Console.WriteLine($"Name of property: {nameof(sampleParam)}");
Func(sampleParam);
}
private static void Func(Sample s)
{
Console.Write($"Name of parameter: {nameof(s)}");
}
}
public class Sample
{
}
Output:
Name of property: sampleParam
Name of parameter: s
Now this is a rather simplistic example. Func exists in the same class as sampleParam and there is only one property so one could derive the name but my assumption is despite your question stating it this way you are looking for a more generalized solution. The problem is that inside func the calling parameter name is not in scope. You could capture it via nameof in the calling method and pass it into func but you shouldn't that would be horrible code for a variety of reasons.
As described what you are doing is intentionally building fragile tightly coupled code which is something developers work very hard to prevent. The caller is not going to know the name of the parameter passed into func is important and shouldn't. This leads me to believe this an xy problem.

Related

Getting the name of a parameter object

I regularly have to export various List<> from within my code to external files. In order to do it in a generic way I wanted to write a function that just takes the name of my variable and then exports according to the fields in that class.
I have that working fine, the only thing what I can't seem to figure out is the name of the variable that I want to export. I can get the type of the class, but that's not what I need. I can get the name of the variable I put it into but that's not what I need either.
Below you'll find the code I'm using:
public class testClass
{
public string firstName {get; set;}
public string lastName {get; set;}
}
private void test()
{
testClass nameOfMyTestClass = new testClass();
// DATA ADDED TO nameOfMyTestClass
...
exportClass(nameOfMyTestClass);
}
public void exportClass(object selectedClass)
{
string objectName = selectedClass.name;
string output = string.Empty;
// GET THE DATA FROM THE SETTINGS
PropertyInfo[] properties = selectedClass.GetType().GetProperties();
foreach (var p in properties)
{
output += "[" + p.Name + "] " + p.GetValue(selectedClass) + Environment.NewLine;
}
// WRITE THE FILE
File.WriteAllText(basePath + #"DATA\" + objectName + ".txt", output, Encoding.UTF8);
}
So I'm passing the variable nameOfMyTestClass as an object into the method exportClass because I want to be able to use this for multiple different classes.
Inside that method I would like to use the name of the variable that I have added as the name of my file: e.g. nameOfMyTestClass.txt
I can get the Class itself by using the GetType() or I can use ToString() but that gives me NAMESPACE.Form1+testClass as a result but I can't find a way to get the actual name of the variable.
Does anybody have an idea how I can accomplish this?
Thanks
You can't get variable names through reflection since they are not present in the compiled assembly's metadata.
But to get the name of the variable, you can use the nameof() operator (introduced with C# 6.0). Note that you would have to add an extra parameter for the name:
exportClass(nameOfMyTestClass, nameof(nameOfMyTestClass));
public void exportClass(object selectedClass, string name)
{ /* ... */ }
The advantage of the nameof operator is, that if you use refactoring (renaming), the passed name will be changed as well, compared to just passing the name in a string literal.
This is not possible because variables don't haves names after they are compiled to IL. But there is a Workaround for you:
void ExportClass(object obj, string className)
{
...
}
var testClass = new TestClass();
ExportClass(testClass, nameof(testClass));
You pass the variable name with nameof to the method and you can use it there.

How does nameof work?

I was just wondering how come nameof from C# 6, can access non static property just like if it was static. Here is an example
public class TestClass
{
public string Name { get; set; }
}
public class Test
{
public Test()
{
string name = nameof(TestClass.Name); // whats so speciall about nameof
//string name2 = TestClass.Name; this won't compile obviously,
}
}
It's not "accessing" the property - that operator is purely a compiler mechanism to inject the "name" of the argument into the code. In this case it will replace nameof(TestClass.Name) with "Name". The fact that it's non-static is irrelevant.
nameof Interpreter gets resolved at compiletime and translated to a static string instead.
In your case nameof(TestClass.Name) you will only return "Name" as a string.
You have to use nameof(TestClass).
With nameof you can minimize redundancy in your code (For instance: you dont have to define a string for a propertyname or something like this by using nameof.
You can also use it to represent a classes name. But be aware! nameof(MyClass)
may not be the same as at runtime if you have an derived class!
For runtime purposes use typeOf or .GetType() instead.
Read more at MSDN

How to handle nameof(this) to report class name

I'd like to use the following C#6 code
var joe = new Self();
Console.WriteLine(joe);
... and get the following output:
joe
The following attempt
class Self {
public string Name { get; set; } = nameof(this);
public override string ToString() {
return Name;
}
}
fails as nameof cannot be applied to this. Is it there a workaround for this problem?
EDIT. The scenario I'm working with assures that no two references point to the same Self object.
No, nameof is designed to refer to the compile-time name of the member you're referring to. If you want an object to have a Name property as part of its state, that is independent of how you get to the Name property - as Frédéric Hamidi says, there could be multiple variables (or none) referring to the same object. Basically you need to differentiate between an object and a variable which happens to refer to that object.
However, if you have a constructor to specify the name, you could then use a couple of tricks to make it easier to get the right name:
class Self
{
public string Name { get; }
public Self([CallerMemberName] string name = null)
{
this.Name = name;
}
}
Then:
class Foo
{
private Self me = new Self(); // Equivalent to new Self("me")
public void SomeMethod()
{
// Can't use the default here, as it would be "SomeMethod".
// But we can use nameof...
var joe = new Self(nameof(joe));
}
}
Maybe you can use the following method:
class Self
{
public override string ToString()
{
return this.GetType().Name;
}
}
You can simply use nameof on the variable itself:
Console.WriteLine(nameof(joe));
Here's a working example using the current Roslyn version
The idea for nameof is to make things type safe for specifying program elements during runtime but with compile time type safety checking.
One should atomize what one wants to display. For example in my error messages I include the pertinent information of the class name and the method as such and its checked, so if I change any of the names they are caught as a compile time error:
class Operation
{
public void Execute()
{
try { ... }
catch (Exception ex)
{
Console.Writeline($"{nameof(Operation)}.{nameof(Execute)} has encountered exception:{Environment.NewLine}{Environment.NewLine}{ex.Message}" );
}
}
}
Output
Operation.Excecute has exception:
...
With that said you should override ToString() and report the class name as such
public override string ToString() { return nameof(Self); }
I usually create an internal constant for it when dealing with long class names:
private const string SomeConst = nameof(Self);
Then you can use that in your code:
Console.WriteLine(SomeConst);

C# Get property value without creating instance?

Is it possible to get value without creating an instance ?
I have this class:
public class MyClass
{
public string Name{ get{ return "David"; } }
public MyClass()
{
}
}
Now I need get the value "David", without creating instance of MyClass.
Real answer: no. It's an instance property, so you can only call it on an instance. You should either create an instance, or make the property static as shown in other answers.
See MSDN for more information about the difference between static and instance members.
Tongue-in-cheek but still correct answer:
Is it possible to get value without creating an instance ?
Yes, but only via some really horrible code which creates some IL passing in null as this (which you don't use in your property), using a DynamicMethod. Sample code:
// Jon Skeet explicitly disclaims any association with this horrible code.
// THIS CODE IS FOR FUN ONLY. USING IT WILL INCUR WAILING AND GNASHING OF TEETH.
using System;
using System.Reflection.Emit;
public class MyClass
{
public string Name { get{ return "David"; } }
}
class Test
{
static void Main()
{
var method = typeof(MyClass).GetProperty("Name").GetGetMethod();
var dynamicMethod = new DynamicMethod("Ugly", typeof(string),
Type.EmptyTypes);
var generator = dynamicMethod.GetILGenerator();
generator.Emit(OpCodes.Ldnull);
generator.Emit(OpCodes.Call, method);
generator.Emit(OpCodes.Ret);
var ugly = (Func<string>) dynamicMethod.CreateDelegate(
typeof(Func<string>));
Console.WriteLine(ugly());
}
}
Please don't do this. Ever. It's ghastly. It should be trampled on, cut up into little bits, set on fire, then cut up again. Fun though, isn't it? ;)
This works because it's using call instead of callvirt. Normally the C# compiler would use a callvirt call even if it's not calling a virtual member because that gets null reference checking "for free" (as far as the IL stream is concerned). A non-virtual call like this doesn't check for nullity first, it just invokes the member. If you checked this within the property call, you'd find it's null.
EDIT: As noted by Chris Sinclair, you can do it more simply using an open delegate instance:
var method = typeof(MyClass).GetProperty("Name").GetGetMethod();
var openDelegate = (Func<MyClass, string>) Delegate.CreateDelegate
(typeof(Func<MyClass, string>), method);
Console.WriteLine(openDelegate(null));
(But again, please don't!)
You can make that property static
public static string Name{ get{ return "David"; } }
Usage:
MyClass.Name;
You requirements do seem strange, but I think you're looking for some kind of metadata. You can use an attribute to achieve this:
public class NameAttribute : Attribute {
public string Name { get; private set; }
public NameAttribute(string name) {
Name = name;
}
}
[Name("George")]
public class Dad {
public string Name {
get {
return NameGetter.For(this.GetType());
}
}
}
[Name("Frank")]
public class Son : Dad {
}
public static class NameGetter {
public static string For<T>() {
return For(typeof(T));
}
public static string For(Type type) {
// add error checking ...
return ((NameAttribute)type.GetCustomAttributes(typeof(NameAttribute), false)[0]).Name;
}
}
Now this code can get names with and without instances:
Console.WriteLine(new Dad().Name);
Console.WriteLine(new Son().Name);
Console.WriteLine(NameGetter.For<Dad>());
Console.WriteLine(NameGetter.For<Son>());
You can make your property static, as pointed out by many others.
public static string Name{ get{ return "David"; } }
Be aware that this means your instances of MyClass will no longer have their own Name property, since static members belong to the class, not the individual object instances of it.
Edit:
In a note, you mentioned that you want to override the Name property in subclasses. At the same time, you want to be able to access it at the class level (access it without creating an instance of your class).
For the static properties, you would simply create a new Name property in each class. Since they are static, you're always (almost always, yay reflection) going to access them using a specific class, so you'd be specifying which version of Name you want to get. If you want to try and hack polymorphism in there and get the name from any given subclass of MyClass, you could do so using reflection, but I wouldn't recommend doing so.
Using the example from your comment:
public class Dad
{
public static string Name { get { return "George"; }
}
public class Son : Dad
{
public static string Name { get{ return "Frank"; }
}
public static void Test()
{
Console.WriteLine(Dad.Name); // prints "George"
Console.WriteLine(Son.Name); // prints "Frank"
Dad actuallyASon = new Son();
PropertyInfo nameProp = actuallyASon.GetType().GetProperty("Name");
Console.WriteLine(nameProp.GetValue(actuallyASon, null)); // prints "Frank"
}
As a side note, since you are declaring a property that has only a getter and it is returning a constant value, I recommend possibly using a const or static readonly variable instead.
public const string Name = "David";
public static readonly string Name = "David";
Usage for both would be the same:
string name = MyClass.Name;
The main benefit (and drawback) of const is that all references to it are actually replaced by its value when the code is compiled. That means it will be a little faster, but if you ever change its value, you will need to recompile ALL code that references it.
Whenever you write C# code, always check if your method and property getter/setter code does anything at all with other instance members of the class. If they don't, be sure to apply the static keyword. Certainly the case here, it trivially solves your problem.
The reason I really post to this question is that there's a bit of language bias at work in some of the answers. The C# rule that you can't call an instance method on a null object is a specific C# language rule. It is without a doubt a very wise one, it really helps to troubleshoot NullReferenceExceptions, they are raised at the call site instead of somewhere inside of a method where it gets very hard to diagnose that the this reference is null.
But this is certainly not a requirement to the CLR, nor of every language that run on the CLR. In fact, even C# doesn't enforce it consistently, you can readily bypass it in an extension method:
public static class Extensions {
public static bool IsNullOrEmpty(this string obj) {
return obj != null && obj.Length > 0;
}
}
...
string s = null;
bool empty = s.IsNullOrEmpty(); // Fine
And using your property from a language that doesn't have the same rule works fine as well. Like C++/CLI:
#include "stdafx.h"
using namespace System;
using namespace ClassLibrary1; // Add reference
int main(array<System::String ^> ^args)
{
MyClass^ obj = nullptr;
String^ name = obj->Name; // Fine
Console::WriteLine(name);
return 0;
}
Create a static property:
public class MyClass
{
public static string Name { get { return "David"; } }
public MyClass()
{
}
}
Get it like so:
string name1 = MyClass.Name;
That is not possible. As Name is an instance property, you can only get its value if you have an instance.
Also, note that you are not talking about a parameter, but about a property.
Create a static class or a static property, and you don't have to explicitly instantiate it.

How can I avoid ref parameters?

I have a method that has 2 ref parameters:
public void ReplaceSomething(ref int code, ref string name)
{
...
}
I want to avoid this, as it is not a good design (and scales poorly). What are my options?
I've though about using an anonymous object, but that doesn't seem like a good idea, either.
Object something = new { code = 1, name = "test" };
ReplaceSomething(something);
Are the code and the name closely linked together? If so, consider creating a type to put the two of them together. Then you can return a value of that type.
Alternatively, you might consider returning a Tuple<int, string>.
(In both cases you can accept an input parameter of the same type, of course. As you haven't shown any of your code, it's not really clear whether you use the existing values of the parameters, or whether they could basically be out parameters.)
Why don't you want to use ref arguments? That seems like a perfectly good way to change some caller values.
The other approach would be to implement a return value. Maybe you need to better explain what the problem is?
If these values are tightly coupled and "belong together" you could define a custom class that holds your properties and either return a new instance (assuming its immutable) of that or update its properties:
class Code
{
public int Value {get;set;}
public string Name {get;set;}
}
public Code UpdateCode(Code code)
{
...
}
If you need to return these values, you can either use a tuple
public Tuple<int, string> ReplaceSomething(int code, string name)
{
...
}
Or create your own class-wrapper that holds the values as properties
public Foo ReplaceSomething(int code, string name)
{
var foo = new Foo(){...};
return foo;
}
class Foo
{
public int IntValue{get;set;}
public string StringValue{get;set;}
}
Why would you change it? ref parameters make sense at times, and if this is one of those times - use them. You could introduce a new class that contains that pair of values, which only makes sense if those values come together often.
I say, keep it.
Based on your question, I could be way off. What do you mean by replacing ref? Are you looking to overload?
public void ReplaceSomething(int code, string name)
{
// ...
}
public void ReplaceSomething()
{
return ReplaceSomething(1, "test");
}
Edit:
ok, so you need to return the code and the name what are the calculations that need to be made? Jon Skeet's answer about a tuple could be right, or you might need a POCO that contains the code the name and the replaced
public void ReplaceSomething(int code, string name)
{
var replaced = new Replaced();
replaced.code = code;
replaced.name = name;
var r;
// do some replacement calculations
replaced.replaced = r;
return replaced;
}
public class Replaced {
public string name {get; set;}
public int code {get; set;}
public string replaced {get; set;}
}

Categories

Resources