string MyVar1 = "bilah bilah";
dosometing(MyVar1);
void dosometing(object MyObject)
{
string VarName = nameof(MyObject); // it givess : "MyObject"
}
But I was expecting "MyVar1" is there a way for that? using dynamic? or ref?
That's not possible. But you can do something like:
string MyVar1 = "bilah bilah";
dosometing(MyVar1, nameof(MyVar1));
void dosometing(string MyString, string VarName)
{
// MyString holds the value
// VarName holds the variable name
}
Maybe this information is usefull for you.
Since you want the value and the name of the property that has changed you could move the method dosomething inside the setter of the property.
(Notice: I am assuming you are actually working with properties and not local variables as shown in your question, and your question is just simplified)
So something like this:
public class Foo
{
private string _myVar1;
public string MyVar1
{
get => _myVar1;
set
{
_myVar1 = value;
DoSomething(value);
}
}
private void DoSomething(string value, [CallerMemberName]string propertyName = "")
{
Console.WriteLine(value);
Console.WriteLine(propertyName);
}
}
The attribute CallerMemberName requires the using System.Runtime.CompilerServices
More Information can be found here: https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.callermembernameattribute
See it in action here: https://dotnetfiddle.net/YvqqdP
Related
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Finding the Variable Name passed to a Function in C#
The class below contains the field city.
I need to dynamically determine the field's name as it is typed in the class declaration
i.e. I need to get the string "city" from an instance of the object city.
I have tried to do this by examining its Type in DoSomething() but can't find it when examining the contents of the Type in the debugger.
Is it possible?
public class Person
{
public string city = "New York";
public Person()
{
}
public void DoSomething()
{
Type t = city.GetType();
string field_name = t.SomeUnkownFunction();
//would return the string "city" if it existed!
}
}
Some people in their answers below have asked me why I want to do this.
Here's why.
In my real world situation, there is a custom attribute above city.
[MyCustomAttribute("param1", "param2", etc)]
public string city = "New York";
I need this attribute in other code.
To get the attribute, I use reflection.
And in the reflection code I need to type the string "city"
MyCustomAttribute attr;
Type t = typeof(Person);
foreach (FieldInfo field in t.GetFields())
{
if (field.Name == "city")
{
//do stuff when we find the field that has the attribute we need
}
}
Now this isn't type safe.
If I changed the variable "city" to "workCity" in my field declaration in Person this line would fail unless I knew to update the string
if (field.Name == "workCity")
//I have to make this change in another file for this to still work, yuk!
{
}
So I am trying to find some way to pass the string to this code without physically typing it.
Yes, I could declare it as a string constant in Person (or something like that) but that would still be typing it twice.
Phew! That was tough to explain!!
Thanks
Thanks to all who answered this * a lot*. It sent me on a new path to better understand lambda expressions. And it created a new question.
Maybe you need this. Works fine.
I found this here.
static void Main(string[] args)
{
var domain = "matrix";
Check(() => domain);
Console.ReadLine();
}
static void Check<T>(Expression<Func<T>> expr)
{
var body = ((MemberExpression)expr.Body);
Console.WriteLine("Name is: {0}", body.Member.Name);
Console.WriteLine("Value is: {0}", ((FieldInfo)body.Member)
.GetValue(((ConstantExpression)body.Expression).Value));
}
Output will be:
Name is: 'domain'
Value is: 'matrix'
I know this is old question, but I was trying to achieve the same and google sent me here. After many hours I finally found a way. I hope somebody else will find this useful.
There are actually more ways to accomplish this:
static void Main(string[] args)
{
GetName(new { var1 });
GetName2(() => var1);
GetName3(() => var1);
}
static string GetName<T>(T item) where T : class
{
return typeof(T).GetProperties()[0].Name;
}
static string GetName2<T>(Expression<Func<T>> expr)
{
return ((MemberExpression)expr.Body).Member.Name;
}
static string GetName3<T>(Func<T> expr)
{
return expr.Target.GetType().Module.ResolveField(BitConverter.ToInt32(expr.Method.GetMethodBody().GetILAsByteArray(), 2)).Name;
}
The first is fastest. The last 2 are approx 20 times slower than the 1st one.
http://abdullin.com/journal/2008/12/13/how-to-find-out-variable-or-parameter-name-in-c.html
city in this case is an instance of type string. When you call .GetType() you return the actual string type, which has no knowledge at all of your particular city instance.
I'm having a hard time seeing why you can't just type "city" in the code as a string literal here, if that's what you need. Perhaps it would help if you shared what you want to use this value for and in what circumstances you will call your DoSomething() function.
At the moment, my best guess is that what you really want to do is reflect the entire Person class to get a list of the fields in that class:
public void DoSomething()
{
MemberInfo[] members = this.GetType().GetMembers();
// now you can do whatever you want with each of the members,
// including checking their .Name properties.
}
Okay, based on your edit I have some more for you.
You can find the name of fields that are decorated with your attribute at run-time like this:
Type t = typeof(Person);
foreach (MemberInfo member in t.GetMembers()
.Where(m =>
m.GetCustomAttributes(typeof(MyCustomAttribute)).Any() ) )
{
// "member" is a MemberInfo object for a Peson member that is
// decorated with your attribute
}
You can also use binding flags in the first GetMembers() call to limit it to just fields, if you want.
You mentioned "i.e. I need to get the string "city" from an instance of the object city."
Are you looking to get the field name from the value of the field.
For example:If there are 2 Person object one with city "New York" and the other with city "London", are you looking for the function to return "city". Is this what you mean by dynamic?
With your current design you will always need to compare the name of the field from the FieldInfo against a string.
What if you instead decouple this so that you hold the identifier to use for comparison purposes during reflection as part of the attribute.
Something like this:
public enum ReflectionFields
{
CITY = 0,
STATE,
ZIP,
COUNTRY
}
[AttributeUsage(AttributeTargets.Field,AllowMultiple=false)]
public class CustomFieldAttr : Attribute
{
public ReflectionFields Field { get; private set; }
public string MiscInfo { get; private set; }
public CustomFieldAttr(ReflectionFields field, string miscInfo)
{
Field = field;
MiscInfo = miscInfo;
}
}
public class Person
{
[CustomFieldAttr(ReflectionFields.CITY, "This is the primary city")]
public string _city = "New York";
public Person()
{
}
public Person(string city)
{
_city = city;
}
}
public static class AttributeReader<T> where T:class
{
public static void Read(T t)
{
//get all fields which have the "CustomFieldAttribute applied to it"
var fields = t.GetType().GetFields().Where(f => f.GetCustomAttributes(typeof(CustomFieldAttr), true).Length == 1);
foreach (var field in fields)
{
var attr = field.GetCustomAttributes(typeof(CustomFieldAttr), true).First() as CustomFieldAttr;
if (attr.Field == ReflectionFields.CITY)
{
//You have the field and you know its the City,do whatever processing you need.
Console.WriteLine(field.Name);
}
}
}
}
public class Program
{
public static void Main(string[] args)
{
PPerson p1 = new PPerson("NewYork");
PPerson p2 = new PPerson("London");
AttributeReader<PPerson>.Read(p1);
AttributeReader<PPerson>.Read(p2);
}
}
You can now freely rename _city field of Person to something else and your calling code will still work since the code using reflection is trying to identify the field using the ReflectionFields enum value set as part of initialization of the attribute set on the field.
Yes its possible !!!
Try this out...
public string DoSomething(object city)
{
return city.GetType().GetProperty("Name",typeof(string)).GetValue(city,null);
}
Two things here.
Number one, as someone above pointed out, you're getting the Type for string, not for Person. So typeof(Person).GetMembers() will get you the list of members.
Number two, and more importantly, it looks like you're misunderstanding the purpose of attributes. In general attributes are used to mark a member for specific processing or to add additional information. Here you're using the name to indicate what processing you want, and the attribute to specify parameters, which is mixing of metaphors, or something.
Abhijeet's answer is more appropriate, you mark the field as a city field, then do what you like with it. Where I disagree is that I would use different attribute classes, rather than an enumeration.
Something like:
public class MyAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Field)]
public class MyCityAttribute : MyAttribute
{
}
[AttributeUsage(AttributeTargets.Field]
public class MyNameAttribute: MyAttribute
{
}
public class Person
{
[MyCity]
public string city = "New York";
[MyCity]
public string workCity = "Chicago";
[MyName]
public string fullName = "John Doe";
public Person()
{
}
public void DoSomething()
{
Type t = typeof(Person);
FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public);
foreach (var field in fields)
{
MyAttribute[] attributes = field.GetCustomAttributes(typeof(MyAttribute));
if (attributes.Count > 0)
{
if (attributes[0] is MyCityAttribute)
{
//Dosomething for city
break;
}
if (attributes[0] is MyNameAttribute)
{
//Dosomething for names
break;
}
}
}
}
}
This would allow you to use different parameters for MyCity vs MyName that would make more sense in the context of processing each.
I think with your 'yuk' comment above, you hit the nail on the head. That you would have to change a string constant if you rename your variable is an indicator that you're doing something wrong.
t.GetField("city", BindingFlags.Public | BindingFlags.Instance);
or you can call GetFields() to get all fields
You need to call get type on the class Person. The iterate the fields of the class as in the answer below
This is not possible (I think it actually is but involes several hacks and using lambdas). If you want to store attributes about a Person and be able to get the name of the attribute easily, I suggest using a Dictionary<TKey, TValue> from the System.Collections.Generic namespace.
And you can always make public properties that wrap the dictionary.
public class Person
{
Dictionary<string, string> attributes = new Dictionary<string, string();
public string City
{
get { return attributes["city"]; }
set { attributes["city"] = value; }
}
public Person()
{
City = "New York";
}
}
And you can get a list of all attributes with attributes.Keys.
Have a look at this post as it looks similar to what you're trying to do:
Finding the variable name passed to a function
(especially Konrad Rudolph's answer) Another approach could be to just add "city" as one of the parameters in the attribute and fish that out later.
You are already looping through the collection of FieldInfo objects. Look for your attribute on those and when you find the FieldInfo that contains your attribute, you have the one you want. Then call .Name on it.
system.reflection.fieldinfo.attributes
Is there a better way to perform type checking inside of properties for custom classes?
For instance:
namespace DataTransferObjects
{
public class sampleDTO
{
private string _fname;
private string _lname;
public string FirstName
{
get;
set {_fname = value == null ? String.Empty : value.ToString(); }
}
public string LastName
{
get;
set { _lname = value == null ? String.Empty : value.ToString(); }
}
} // class
} // namespace
.
.
.
sampleDTO sDTO = new sampleDTO();
sDTO.FirstName = DataGridViewSample.Rows[0].Cells["FirstName"].Value;
sDTO.LastName = DataGridViewSample.Rows[0].Cells["LastName"].Value;
The problem is that the compiler will not allow an object to be passed into the class.
I could rewrite this as follows:
namespace DataTransferObjects
{
public class sampleDTO
{
private string _fname;
private string _lname;
public object FirstName
{
get { return (object)_fname; }
set {_fname = value == null ? String.Empty : value.ToString(); }
}
public object LastName
{
get { return (object)_lname; }
set { _lname = value == null ? String.Empty : value.ToString(); }
}
} // class
} // namespace
But this seems too clunky, since I now have to cast any calls as follows
string tempFirstName = sDTO.FirstName.ToString();
Any words of wisdom from the community?
The correct thing to do is to use something like your first example, but cast the value to a string before you set the property:
sDTO.FirstName = DataGridViewSample.Rows[0].Cells["FirstName"].Value as string;
Your example does need to be fixed a little, though:
public string FirstName
{
get {return _fname;}
set {_fname = value ?? String.Empty; }
}
Is there a better way to perform type checking inside of properties for custom classes?
Do you mean null checking? Because that's what the code in the property is doing. You could shorten each setter to something like:
_fname = value ?? string.Empty;
The null coalescing operator essentially does what your conditional operator is doing in this case. Return the first value if it is not null, or the second value if it is. And you don't need .ToString() because the value is already a string.
But the "type checking" is already done by default, only a string can be passed to that property.
The problem is that the compiler will not allow an object to be passed into the class.
Well, no. C# is statically typed. So you'd have to pass a string. Which could be as simple as this:
sDTO.FirstName = DataGridViewSample.Rows[0].Cells["FirstName"].Value.ToString();
or perhaps:
sDTO.FirstName = (string)DataGridViewSample.Rows[0].Cells["FirstName"].Value;
I could rewrite this as follows: [...]
You definitely don't want to make the properties be of type object, because then any time you read the property you'd have to cast/convert/etc. The model itself would no longer be encapsulating what it actually represents and it would be up to all consuming code to do the work for it.
What you can do is maybe add other properties/methods for this purpose? Consider a method such as:
public void SetFirstNameFromObject(object firstName)
{
this.FirstName = firstName.ToString();
}
Or if you want to put it in a property:
public object FirstNameAsObject
{
get { return this.FirstName; }
set { this.FirstName = value.ToString(); }
}
(Including relevant error checking appropriately of course, left out of this example for brevity.)
Essentially you'd separate the conversion of the types from the actual model properties, creating a kind of pass-through operation which serves only to convert types.
So im new at C# and i need to know if what i want to do is possible and how heres what I have,
public static class Sempre
{
public static string Raca = "";
}
// Sempre.Raca - can use like this
Now What I want to do is set a variable like thing = "example", and after this call Sempre but with the variable something like, Sempre.thing, but because it's a variable it would actually be Sempre.example.
Example same use I want in php,
$example = mean;
$_SESSION['name'.$example];
would create $_SESSION [namemean];
You can setup your type with an indexer. http://msdn.microsoft.com/en-us/library/6x16t2tx.aspx. To use the indexer, you are required to have an instance class rather than a static one. If you really need to, you can use the singleton pattern to get "static" behavior.
Here is an example of using an indexer:
public class Sempre
{
private Dictionary<string, string> _values = new Dictionary<string, string>();
public string this[string key]
{
get { return _values[key]; }
set { _values[key] = value; }
}
}
You can use it like this:
Sempre sempre = new Sempre();
sempre["example"] = "my value";
string thing = "example";
Console.WriteLine(sempre[thing]);
Generally speaking you can not do this with objects in C# since the code is precompiled prior to runtime.
If you are specifically looking for an implementation of http session state, like you have in the PHP code example then this could be done. Session State is exposed at System.Web.SessionState.HttpSessionState and can be accessed via concatenated strings like in your example like this.
String example = "mean";
Session["name" + example] = 'bar';
//Session["namemean"] is now set to value of 'bar'
If you're only looking to do string substitution, you can also do something like this:
public class StringConstants
{
public static string YES = "yes";
public static string NO = "no";
}
then elsewhere
public void printmessage(bool value)
{
if (value)
{
Console.writeline (string.Format "I Say {0}", StringConstants.YES);
}
else
{
Console.writeline (string.Format "I Say {0}", StringConstants.NO);
}
}
Documentation on string.Format for insertions and compositions is here
I have a problem with downcasting, how do I convert the string "Label" to the class type Label for casting and is it possible to reach the 'Texts' class?
public class GFXObject
{
// Constructor etc...
}
public class Label : GFXObject
{
public Texts Text = new TextClass();
// Constructor etc...
}
public class Button : GFXObject
{
// Constructor etc...
}
public class Texts
{
public string Text = "empty";
// Constructor etc...
}
// My List of objects
Dictionary<string, GFXObject> objects;
// Disregarding any troubleshooting
public void ChangeText(string classtype, string name, string text)
{
// How do I convert the string classtype to a ClassType
((classtype)objects[name]).Text.Text = text;
// If parameters would be equal to "Label", "label", "changed":
// ((Label)objects["label"].Text.Text = "changed";
}
Is it possible to use the ChangeText function if extended or modified?
You can do that only via reflection:
public void ChangeText(string classtype, string name, string text)
{
var type = Type.GetType(classtype);
type.GetProperty("Text").SetValue(objects[name], text);
}
Please note that classtype needs to be an assembly-qualified name if the method is in a different assembly than the type. If it is in the same assembly it needs to be fully qualified, i.e. including the namespace.
If that's a problem, you could get rid of the classtype parameter and use this method:
public void ChangeText(string name, string text)
{
var type = objects[name].GetType();
type.GetProperty("Text").SetValue(objects[name], text);
}
Another possibility would be to make use of the DLR and the dynamic keyword:
public void ChangeText(string name, string text)
{
dynamic item = objects[name];
item.Text = text;
}
Please note that every code that uses the dynamic item variable is evaluated only at runtime. This means that this code compiles even if there is no Text property on that particular item. It will then throw an exception at runtime.
Having said all that, the correct solution to this problem would be to introduce a base class or interface that holds the Text property.
Another solution, if the amount of classes being used is small, could be to create a helper to set the property, like:
public void ChangeText(string classtype, string name, string text)
{
switch(classtype)
{
case "ClassType1":
((ClassType1)objects[name]).Text = text;
break;
case "ClassType2":
((ClassType2)objects[name]).Text = text;
break;
etc...
default:
throw new InvalidOperationException("ClassType {0} is not supported", classtype);
}
I want to slap a simple class together to pick out QueryString variables from an HTTP request that gets sent to my application. The variables are not always in the same order, but they're always there. I want to assign the variables in my class the values of the corresponding variables from the request, but I have no idea how to do this.
Code snippets:
MyHTTPRequest ar = new MyHTTPRequest("GET /submit.php?variableOne=value&variableTwo=someothervalue HTTP/1.1"); // Leaving out the rest for now
class MyHTTPRequest
{
public string variableOne;
public string variableTwo;
public string variableThree;
private string[] properties = { "variableOne", "variableTwo", "variableThree" }; // I know they're not actually properties
public MyHTTPRequest(string request)
{
string[] variablePars = request.Substring(16, request.Length - 24).Split('&'); // variablePars now contains "variableOne=value" & "variableTwo=someothervalue"
foreach (string variablePar in variablePars)
{
if (properties.Contains(variablePar.Split('=')[0])) // variableOne, variableTwo, variableThree
{
// Assign the correct variable the value
<???> = variablePar.Split('=')[1]; // I don't know how to pull this one off. variablePar.Split('=')[0] should contain the name of the variable.
}
}
}
}
Any input?
I'm sure a similar question already exists, but I did not know what to titel or tag this with.
Use the System.Web.HttpUtilityClass.ParseQueryString. It returns a NameValueCollection just like you get in ASP.NET with Request.QueryString.
// assuming you can parse your string to get your string to this format.
string queryStringText = "variableOne=value&variableTwo=someothervalue";
NameValueCollection queryString =
HttpUtility.ParseQueryString(queryStringText);
string variable1 = queryString["variableOne"];
string variable2 = queryString["variableTwo"];
Why not turn it around?
class MyHTTPRequest {
public string variableOne { get { return _values["variableOne"]; } }
public string variableTwo { get { return _values["variableTwo"]; } }
public string variableThree { get { return _values["variableThree"]; } }
NameValueCollection _values;
public MyHTTPRequest(string queryStringText) {
_values = HttpUtility.ParseQueryString(queryStringText);
}
}
You could use reflection to do this as follows:
PropertyInfo property = YourDtoClass.GetType().GetProperty("ThePropertyName");
if (property != null)
{
property.SetValue(theTargetObject, theValue);
}
Here we first get the property of the class where your properties are defined (via reflection and the property name). If a property is found with the desired name, we then set the property value on the target object.
Or using fields instead of properties:
FieldInfo field = YourDtoClass.GetType().GetField("theFieldName");
if (field != null)
{
field.SetValue(theTargetObject, theValue);
}
Update
This technique is only really safe (from a security perspective as others commented) if the target object that you are setting values on is purely a DTO, where all fields\properties are intended to be populated by query string values. This was the original viewpoint of my answer. If the target object contains fields that should not be set from query string values, then do not use this technique, as fields\properties that are not intended to be set from query string values, could be.
If your target object is a DTO, then the above is fine. I am assuming that this is the case.
http://msdn.microsoft.com/en-us/library/system.web.httprequest.querystring.aspx