I'm making a graphic control class Info which should display some text on screen. The text is some object's string. I'd like to be able to get that object's latest value from within an instance of Info class.
class Info
{
public string Text;
}
void Program()
{
ClassA obj = new ClassA();
obj.name = "Instance of ClassA";
Info wind1 = new Info();
wind1.Text = obj.name; // this just copies current value, but should be a reference or something
/* obj.name value changes several times before it's time to display it again */
// Info window drawing method
foreach (var item in Windows) // Windows is List<Info>
Draw(item.Text); // this doesn't get the latest value
}
How should I change the code so I can get the latest string value from within the drawing section?
Update: If you need something that'll work for any type, you'll have to use delegates. For example:
class Info
{
private Func<string> getText;
public Info(Func<string> getText)
{
getText = getText;
}
public string Text
{
get
{
return getText();
}
}
}
void Program
{
ClassA obj = new ClassA();
obj.name = "Instance of ClassA";
Info wind1 = new Info(() => obj.name);
// Now do your stuff.
}
In this case, Info is given an anonymous function that returns a string. When you access its Text property, the function is evaluated to retrieve that string. How the string is retrieved, and where it comes from, is determined by the client code (i.e. the Program method). This way, Info doesn't rely on any particular type.
You could pass the ClassA object into your Info instance, so that it can get the value of.name itself.
Something like this, perhaps?
class Info
{
public Info(ClassA obj)
{
TheObject = obj;
}
public ClassA TheObject
{
get;
set;
}
public string Text
{
get
{
return TheObject.name;
}
}
}
void Program
{
ClassA obj = new ClassA();
obj.name = "Instance of ClassA";
Info wind1 = new Info(obj);
// Now do your stuff.
}
Related
I have a custom class from which I create over 200 objects for a Gui.
In my main class with my business logic I want to apply the instantiation of all my objects, attach them to an event handler and set their Name. Instead of doing all this by hand for every object I thought to create a method that takes as parameters a "params" list of my objects. The problem is that this method seems to work out a "copy" of my objects instead the reference of those. What I have so far is:
My object base class:
public class MyObject
{
... // this works
}
My business class now (what works):
public class Logic
{
public MyObject Object001, Object002,... Object200; // note that they are not instantiated yet
public Logic()
{
Object001 = new MyObject();
Object001.Name = nameof(Object001);
Object001.PropertyChanged += (s, e) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
Object002 = new MyObject();
Object002.Name = nameof(Object002);
Object002.PropertyChanged += (s, e) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
...
Object200 = new MyObject();
Object200.Name = nameof(Object200 );
Object200.PropertyChanged += (s, e) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
}
}
My desired business class (what has not worked):
public class Logic
{
public MyObject Object001, Object002,... Object200; // note that they are not instantiated yet
public Logic()
{
InstantiateAllObjects(Object001, Object002, ..., Object200); // here my 200 objects!
}
private void InstantiateAllObjects(params MyObject[] list)
{
for (int i=0; i<list.Length; i++)
{
// if(list[i]==Object001) Console.WriteLine("Object001== null?: " + (Object001 == null)); --> this executes for EVERY object, instead for only Object001!!
MyObject obj = list[i];
obj = new MyObject();
obj.Name = nameof(obj); // why "nameof(list[i])" didn't work?
obj.PropertyChanged += (s, e) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
// if (list[i] == Object001) Console.WriteLine("Object001== null?: " + (Object001== null)); --> this executes again for EVERY object AND (Object001== null) is ALWAYS true!!
}
}
}
Can anybody explain me why my method seems not to create my objects?
Thanks in advance for your time and help!
EDIT
In my opinion, the problem seems to be i have to pass a reference to these declared objects in the 'params' list of my method... is it possible? how? I tried to use the modifiers "out" and "ref" near the "params" in the method, but with "params" seems not to be possible...
EDIT2
Following some suggestions I created in my class: logic an object list:
MyObject[] list = new MyObject[] { Object001, Object002, ..., Object200 };
InstantiateAllObjects(ref list);
and modified my method as per private void InstantiateAllObjects(ref MyObject[] list) iterating inside over list[i], but unfortunately with the same wrong result...
and also tried
List<MyObject> list = new List<MyObject>() { Object001, Object002, ..., Object200 };
InstantiateAllObjects(ref list);
and modified my method as per private void InstantiateAllObjects(ref List<MyObject> list) iterating inside over list[i], but unfortunately also with the same wrong result...
Forget about all those Object001, Object002 etc fields. Just use a new List<MyObject>() and add your objects into it inside the for-loop in your InstantiateAllObjects.
public class Logic
{
private readonly List<MyObject> allMyObjects; // note that they still are not instantiated yet
public Logic()
{
cont int amount = 200;
allMyObjects = new List<MyObject>(amount); // reserve space, but all are still null
InstantiateAllObjects(allMyObjects, amount);
}
private void InstantiateAllObjects(List<MyObject> list, int amount)
{
for (int i=0; i<amount; i++)
{
MyObject obj = new MyObject();
obj.Name = "Object" + (i+1).ToString("000");
obj.PropertyChanged += (s, e) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
list.Add(obj); // place the newly created object in the list
}
}
}
Your original test if(list[i]==Object001) fires every time, because both list[i] (for every i) and Object001 are null.
Also note that you can have multiple references to one instance of your MyObject (this already happens when you pass the reference as parameter to some method). The fact that one of those is called "Object001" is not important and in fact unknown to the instance. That is why nameof(list[i]) cannot return "Object001".
Another try, based on Hans Kesting'a answer and anna's statement
2) the name of every object will be (very) different one to another,
it is here just that i used the indexes 001...200 to concept the idea,
To avoid any trouble with accessing the fields and to regard what you wrote in the comments, no getter/setter is used and everything is public. Not the best approach but well, compared to handling 200 separate objects...
public class Logic
{
public List<MyObject> MyObjectList;
public List<string> MyObjectNames;
public Logic()
{
var anotherClass = new AnotherClass();
MyObjectNames = new List<string>() {"Object01", "Object02", "Object03"}; // either add your names here...
MyObjectNames.Add("Object04"); // or add additional names this way
//MyObjectNames.AddRange(anotherNameList); // or add another list or use Linq or whatever
MyObjectList = anotherClass.InstantiateAllObjects(MyObjectNames);
}
}
public class AnotherClass
{
public List<MyObject> InstantiateAllObjects(List<string> nameList)
{
var objectList = new List<MyObject>(nameList.Count);
foreach (var name in nameList)
{
objectList.Add(new MyObject(){Name = name});
}
return objectList;
}
}
Does this meet your requirements?
If you prefer a Dictionary, it's similar:
public class Logic
{
public Dictionary<string, MyObject> MyObjectDict;
public List<string> MyObjectNames;
public Logic()
{
var anotherClass = new AnotherClass();
MyObjectNames = new List<string>() { "Object01", "Object02", "Object03" }; // either add your names here...
MyObjectNames.Add("Object04"); // or add additional names this way
//MyObjectNames.AddRange(anotherNameList); // or add another list or use Linq or whatever
MyObjectDict = anotherClass.InstantiateAllObjects(MyObjectNames);
// objects in dict can be accessed directly by their names:
var object01 = MyObjectDict["Object01"];
}
}
// You can access in derived classes or any other classes
public class DerivedLogic : Logic
{
public void SomeFunc()
{
var object01 = MyObjectDict["Object01"];
}
public void SomeOtherFunc(string objectName)
{
var object01 = MyObjectDict[objectName];
}
}
public class AnotherClass
{
public Dictionary<string, MyObject> InstantiateAllObjects(List<string> nameList)
{
var objectList = new Dictionary<string, MyObject>(nameList.Count);
foreach (var name in nameList)
{
// check if object with name does not already exist.
if(!objectList.ContainsKey(name)
{
// For your property changed assignment, you can separate the object creation and DIctionary/List assignment
var obj = new MyObject() { Name = name };
obj.PropertyChanged += (s, e) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
objectList.Add(name, obj);
}
// else .... doe something
}
return objectList;
}
}
All of those arguments are being passed by value. You're passing the references, but the InstantiateAllObjects method can't change the values of any of the fields.
Simplifying this a bit, it's a little like having code like this:
string x = "Original value";
// This copies the value of x into the array
string[] array = new string[] { x };
// This changes the array element, but doesn't affect the x variable at all
array[0] = "Different value";
// Still prints "Original value", because x hasn't changed
Console.WriteLine(x);
As noted in comments, using a list is likely to be a much better approach than lots of different fields here.
Use a class (can be the same as the one with the logic) to hold your MyObject Fields, pass it into a function that uses reflection to populate the fields.
// Class with Fields
public class MyObjectCollection
{
public MyObject Object001;
public MyObject ObjTwo;
}
public class Logic
{
// Init logic
public void Initialise(object controls)
{
Type targType = typeof(MyObject);
var t = controls.GetType();
// iterate all fields of type MyObject
foreach(var fi in t.GetFields().Where(f=>f.FieldType == targType))
{
// initialise as required.
var o = new MyObject();
o.Name = fi.Name;
fi.SetValue(controls, o);
}
}
}
If the field name is not enough for the object name you could use Attributes on the fields to direct initialisation.
This should do the job. It is a reflection-based approach and what it does is:
find all public instance fields
use only those whose name contains Object
create a new instance of MyObject and store that in the field
public void InstantiateAllObjects()
{
foreach (FieldInfo field in this.GetType()
.GetFields(BindingFlags.Public | BindingFlags.Instance)
.Where(x => x.Name.Contains("Object")))
{
MyObject obj= new MyObject();
obj.PropertyChanged += (s, e) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
field.SetValue(this, obj);
}
}
If you add above method to your Logic class, you can then call it without having to explicitly pass Object001, Object002 etc. to it.
public class Logic
{
public MyObject Object001, Object002, ... Object200;
public Logic()
{
this.InstantiateAllObjects();
}
}
EDIT: Differently named fields
If the fields do not share a common prefix (that is, if they are not all named Object + ...), there are other ways to get the fields:
.Where(x => x.FieldType == typeof(MyObject))
yields only the fields whose type is MyObject.
You could also create an attribute
[AttributeUsage(AttributeTargets.Field)]
public sealed class FieldIWantToSetAttribute : Attribute { }
and apply that to all fields you want to set, e.g.
public class Logic
{
[FieldIWantToSet] public MyObject Object001; // will be set
[FieldIWantToSet] public MyObject Foo; // will be set
public MyObject Bar; // will not be set
}
Then, change the Where to
.Where(x => x.GetCustomAttribute<FieldIWantToSet>() != null)
Please however note that 1. you should definitely use caching. Reflection without caching is expensive, and 2. please overthink your design - why exactly do you feel the need to expose 200 fields for every other class to see?
I am trying to create a Class Method which can be called to Query the Database. The function itself works but for some reason, when the Array is returned, they're not set.
My function code is:
public Configuration[] tbl_bus(string type, string match)
{
// Create Obejct Instance
var db = new rkdb_07022016Entities2();
// Create List
List<Configuration> ConfigurationList = new List<Configuration>();
// Allow Query
if (type.ToLower() == "bustype")
{
foreach (var toCheck in db.tblbus_business.Where(b => b.BusType == match))
{
// Create Class Instance
var model = new Configuration { Name = toCheck.Name, BusinessID = toCheck.BusinessID };
// Append to the property
ConfigurationList.Add(model);
}
}
else if (type.ToLower() == "businessid")
{
foreach (var toCheck in db.tblbus_business.Where(b => b.BusinessID == match))
{
// Create Class Instance
var model = new Configuration { Name = toCheck.Name, BusinessID = toCheck.BusinessID };
// Append to the property
ConfigurationList.Add(model);
}
}
return ConfigurationList.ToArray();
}
And my Configuration code is:
public class Configuration
{
// Properties of the Database
public string Name { get; set; }
public string BusinessID { get; set; }
public string Address { get; set; }
}
public Configuration Config { get; set; }
public Controller()
{
this.Config = new Configuration();
}
On my Handler I am doing:
// Inside the NameSpace area
Controller ctrl;
// Inside the Main Void
ctrl = new Controller();
ctrl.tbl_bus("bustype", "CUS");
context.Response.Write(ctrl.Config.Name);
I tried watching the Class function and it does create the Array, only, when I watch the ctrl.Config.Name it is always set to NULL. Could anyone possibly help me in understanding why the return isn't actually setting the properties inside the Configuration class?
Edit: The function does run and it fetches 3006 rows of Data when matching the bus_type to customer. (Its a large Database) - Only, the properties are never set on return.
Edit: Is there a specific way to return an Array to a Class to set the Properties?
Thanks in advance!
Change your Configs in Controller to array
public Configuration[] Configs { get; set; }
Change your tbl_bus function to void, and set the Configs inside the function.
public void tbl_bus(string type, string match)
{
// do your code
// set the configs here
Configs = ConfigurationList.ToArray();
}
Hope it helps.
Although this is not a complete answer to your question, the problem probably lies in the fact that you're not doing anything with the array returned by the method. You're simply discarding it right away. If you change your code to
ctrl = new Controller();
Configuration[] config = ctrl.tbl_bus("bustype", "CUS");
you will be able to reference the array later on.
Console.WriteLine(config.Length);
Now you can use it to set any properties you like.
I am attempting to list the currently installed printers using PrinterSettings.StringCollection. However, I get this error:
Object Reference not set to an instance of an object
Code is as follows:
namespace DropDownLibrary
{
public class DropDownExample : DSDropDownBase
{
public DropDownExample() : base("item") { }
public static PrinterSettings.StringCollection InstalledPrinters { get; }
public override void PopulateItems()
{
// The Items collection contains the elements
// that appear in the list.
Items.Clear();
// Create a number of DynamoDropDownItem objects
// to store the items that we want to appear in our list.
var newItems = new List<DynamoDropDownItem>();
{
foreach (String name in InstalledPrinters)
{
new DynamoDropDownItem("{0}", name);
}
};
Items.AddRange(newItems);
// Set the selected index to something other
// than -1, the default, so that your list
// has a pre-selection.
SelectedIndex = 0;
}
public override IEnumerable<AssociativeNode> BuildOutputAst(List<AssociativeNode> inputAstNodes)
{
// Build an AST node for the type of object contained in your Items collection.
var intNode = AstFactory.BuildIntNode((int)Items[SelectedIndex].Item);
var assign = AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), intNode);
return new List<AssociativeNode> { assign };
}
}
}
This is covered in this post. The 'Object reference not set to instance of an Object" error is caused by you trying to use a variable that is null. For instance, you can get a null reference error by doing:
object nullObject = null;
nullObject.ToString():
In your code, it doesn't look like the value for InstalledPrinters ever gets set.
Before your code reaches this line:
foreach (String name in InstalledPrinters)
It looks like you copy pasted this from this link:
public static PrinterSettings.StringCollection InstalledPrinters { get; }
This is a property on the PrinterSettings class that you can access. You should access it like so:
var installedPrinters = System.Drawing.Printing.PrinterSettings.InstalledPrinters;
foreach (String name in installedPrinters)
I am trying to create a generic method where I have to append some string to Generic data type and create instance of that appended string.
Eg:
I have two classes
Object1,
Object2,
Object3,
Object4,....Object100 and
Object1Address,
Object2Address,
Object3Address,
Object4Address,....Object100Address
Right now I have method for each Object like MethodObject1(), MethodObject2(),MethodObject3(), MethodObject4()
MethodObject1()
{
Object1 object = new Object1();
Object1Address objectAddress = new Object1Address();
TestMethod();
}
MethodObject2()
{
Object2 object = new Object2();
Object2Address objectAddress = new Object2Address();
TestMethod();
}
MethodObject3()
{
Object3 object = new Object3();
Object3Address objectAddress = new Object3Address();
TestMethod();
}
MethodObject4()
{
Object4 object = new Object4();
Object4Address objectAddress = new Object4Address();
TestMethod();
}
.
.
.
MethodObject100()
{
Object100 object = new Object100();
Object100Address objectAddress = new Object100Address();
TestMethod();
}
But there are around 100 object so I have to create 100 methods in similar way.
So I thought of creating an generic method.
There is a method which returns only the an array of Object name from an XML file.
Eg: ObjectName[] objectName = GetObjects(); // Returns an array of Object Names from XML file so that
objectName[0] = Object1;
objectName[1] = Object2;
objectName[2] = Object3;
objectNmae[3] = Object4;
.
.
.
objectName[99] = Object100;
I am looping through objectName array
foreach(var objectItem in objectName)
{
MethodName<objectItem>();
}
In my generic method I can create an instance of object, like
MethodName<T>()
{
T t = new T();
Some how I have to get the name of T and append Address to T
So that I can create TAddress instance like
TAddress tAddress = new TAddress();
}
Is there any way I can do this using C sharp?
Even with the edits, I still can't follow what you're asking for. However, in an attempt to make forward progress, I'll offer an answer that might at least help isolate what you want.
public class ThingWithAddress<T>
{
public T Item { get; private set; }
public string Address { get; private set; }
public static ThingWithAddress<T> Create(T item, string address)
{
return new ThingWithAddress<T>
{
Item = item,
Address = address,
};
}
}
Then you can get an object that has both a person and address like:
Person person = ...;
var personWithAddress = ThingWithAddress.Create(person, "some address");
Don't take this the wrong way, but you might need to learn enough C# to formulate a good question, since as it stands, the question seems confusing and inconsistent.
Your case doesn't really require a generic method.
What you probably want is to override ToString method in your classes.
class PersonAddress()
{
public override string ToString()
{
return string.Concat(this.Street, ", ", this.City, ", ", this.Postcode);
}
}
class Person()
{
public override string ToString()
{
return string.Concat(this.Name, ", ", this.PersonAddress.ToString());
}
}
Notice how Person class reuses PersonAddress.ToString() method.
I would like to get property name when I'm in it via reflection. Is it possible?
I have code like this:
public CarType Car
{
get { return (Wheel) this["Wheel"];}
set { this["Wheel"] = value; }
}
And because I need more properties like this I would like to do something like this:
public CarType Car
{
get { return (Wheel) this[GetThisPropertyName()];}
set { this[GetThisPropertyName()] = value; }
}
Since properties are really just methods you can do this and clean up the get_ returned:
class Program
{
static void Main(string[] args)
{
Program p = new Program();
var x = p.Something;
Console.ReadLine();
}
public string Something
{
get
{
return MethodBase.GetCurrentMethod().Name;
}
}
}
If you profile the performance you should find MethodBase.GetCurrentMethod() is miles faster than StackFrame. In .NET 1.1 you will also have issues with StackFrame in release mode (from memory I think I found it was 3x faster).
That said I'm sure the performance issue won't cause too much of a problem- though an interesting discussion on StackFrame slowness can be found here.
I guess another option if you were concerned about performance would be to create a Visual Studio Intellisense Code Snippet that creates the property for you and also creates a string that corresponds to the property name.
Slightly confusing example you presented, unless I just don't get it.
From C# 6.0 you can use the nameof operator.
public CarType MyProperty
{
get { return (CarType)this[nameof(MyProperty)]};
set { this[nameof(MyProperty)] = value]};
}
If you have a method that handles your getter/setter anyway, you can use the C# 4.5 CallerMemberName attribute, in this case you don't even need to repeat the name.
public CarType MyProperty
{
get { return Get<CarType>(); }
set { Set(value); }
}
public T Get<T>([CallerMemberName]string name = null)
{
return (T)this[name];
}
public void Set<T>(T value, [CallerMemberName]string name = null)
{
this[name] = value;
}
I'd like to know more about the context in which you need it since it seems to me that you should already know what property you are working with in the property accessor. If you must, though, you could probably use MethodBase.GetCurrentMethod().Name and remove anything after get_/set_.
Update:
Based on your changes, I would say that you should use inheritance rather than reflection. I don't know what data is in your dictionary, but it seems to me that you really want to have different Car classes, say Sedan, Roadster, Buggy, StationWagon, not keep the type in a local variable. Then you would have implementations of methods that do the proper thing for that type of Car. Instead of finding out what kind of car you have, then doing something, you then simply call the appropriate method and the Car object does the right thing based on what type it is.
public interface ICar
{
void Drive( decimal velocity, Orientation orientation );
void Shift( int gear );
...
}
public abstract class Car : ICar
{
public virtual void Drive( decimal velocity, Orientation orientation )
{
...some default implementation...
}
public abstract void Shift( int gear );
...
}
public class AutomaticTransmission : Car
{
public override void Shift( int gear )
{
...some specific implementation...
}
}
public class ManualTransmission : Car
{
public override void Shift( int gear )
{
...some specific implementation...
}
}
Use MethodBase.GetCurrentMethod() instead!
Reflection is used to do work with types that can't be done at compile time. Getting the name of the property accessor you're in can be decided at compile time so you probably shouldn't use reflection for it.
You get use the accessor method's name from the call stack using System.Diagnostics.StackTrace though.
string GetPropertyName()
{
StackTrace callStackTrace = new StackTrace();
StackFrame propertyFrame = callStackTrace.GetFrame(1); // 1: below GetPropertyName frame
string properyAccessorName = propertyFrame.GetMethod().Name;
return properyAccessorName.Replace("get_","").Replace("set_","");
}
FWIW I implemented a system like this:
[CrmAttribute("firstname")]
public string FirstName
{
get { return GetPropValue<string>(MethodBase.GetCurrentMethod().Name); }
set { SetPropValue(MethodBase.GetCurrentMethod().Name, value); }
}
// this is in a base class, skipped that bit for clairty
public T GetPropValue<T>(string propName)
{
propName = propName.Replace("get_", "").Replace("set_", "");
string attributeName = GetCrmAttributeName(propName);
return GetAttributeValue<T>(attributeName);
}
public void SetPropValue(string propName, object value)
{
propName = propName.Replace("get_", "").Replace("set_", "");
string attributeName = GetCrmAttributeName(propName);
SetAttributeValue(attributeName, value);
}
private static Dictionary<string, string> PropToAttributeMap = new Dictionary<string, string>();
private string GetCrmAttributeName(string propertyName)
{
// keyName for our propertyName to (static) CrmAttributeName cache
string keyName = this.GetType().Name + propertyName;
// have we already done this mapping?
if (!PropToAttributeMap.ContainsKey(keyName))
{
Type t = this.GetType();
PropertyInfo info = t.GetProperty(propertyName);
if (info == null)
{
throw new Exception("Cannot find a propety called " + propertyName);
}
object[] attrs = info.GetCustomAttributes(false);
foreach (object o in attrs)
{
CrmAttributeAttribute attr = o as CrmAttributeAttribute ;
if (attr != null)
{
// found it. Save the mapping for next time.
PropToAttributeMap[keyName] = attr.AttributeName;
return attr.AttributeName;
}
}
throw new Exception("Missing MemberOf attribute for " + info.Name + "." + propertyName + ". Could not auto-access value");
}
// return the existing mapping
string result = PropToAttributeMap[keyName];
return result;
}
There's also a custom attribute class called CrmAttributeAttribute.
I'd strongly recommend against using GetStackFrame() as part of your solution, my original version of the solution was originally the much neater:
return GetPropValue<string>();
But it was 600x slower than the version above.
Solution # 1
var a = nameof(SampleMethod); //a == SampleMethod
var b = nameof(SampleVariable); //b == SampleVariable
var c = nameof(SampleProperty); //c == SampleProperty
Solution # 2
MethodBase.GetCurrentMethod().Name; // Name of method in which you call the code
MethodBase.GetCurrentMethod().Name.Replace("set_", "").Replace("get_", ""); // current Property
Solution # 3
from StackTrace:
public static class Props
{
public static string CurrPropName =>
(new StackTrace()).GetFrame(1).GetMethod().Name.Replace("set_", "").Replace("get_", "");
public static string CurrMethodName =>
(new StackTrace()).GetFrame(1).GetMethod().Name;
}
you just need to call Props.CurrPropName or Props.CurrMethodName
Solution # 4
Solution for .NET 4.5+:
public static class Props
{
public static string GetCallerName([System.Runtime.CompilerServices.CallerMemberName] String propertyName = "")
{
return propertyName;
}
}
usage: Props.GetCallerName();
Yes, it is!
string test = "test string";
Type type = test.GetType();
PropertyInfo[] propInfos = type.GetProperties();
for (int i = 0; i < propInfos.Length; i++)
{
PropertyInfo pi = (PropertyInfo)propInfos.GetValue(i);
string propName = pi.Name;
}
Try using System.Diagnostics.StackTrace to reflect on the call stack. The property should be somewhere in the call stack (probably at the top if you're calling it directly from the property's code).