Accessing object properties from string representations - c#

I've got a custom object (example only code for ease of understanding) ...
public class MyClass
{
private string name;
private int increment;
private Guid id;
public string Name
{
get { return name; }
set { name = value; }
}
public int Increment
{
get { return increment; }
set { increment = value; }
}
public Guid Id
{
get { return id; }
set { id = value; }
}
}
... and a custom collection of this class ...
public class MyClassCollection : Collection<MyClass>
{
}
I was looking to write a Sort routine for the collection which will have the following public method ...
public void Sort(params string[] sortProperties)
{
if (sortProperties == null)
{
throw new ArgumentNullException("sortProperties", "Parameter must not be null");
}
if ((sortProperties.Length > 0) && (Items.Count > 1))
{
foreach (string s in sortProperties)
{
// call private sort method
Sort(s);
}
}
}
... and the private Sort method would take a parameter of the property name ...
private void Sort(string propertyName)
{
}
What I want to do is be able to pass in a set of property names into the method ...
MyClassCollection current = new MyClassCollection();
// setup a objects in the collection
current = GetCollectionData();
// sort by Name, then by Increment
current.Sort("Name", "Increment");
Using the property names passed into the method I want to be able to check to see if it has a property of that name, if so work out what type it is and then run through a sort of it.
The interim workaround which I have currently got is ...
private void Sort(string propertyName)
{
// convert to List
List<MyClass> myCurrentClass = Items as List<MyClass>;
// sort
if (myCurrentClass != null)
{
switch (propertyName)
{
case "Name":
myCurrentClass.Sort(delegate(MyClass myClassOne, MyClass myClassTwo)
{
return
Comparer<string>.Default.Compare(myClassOne.Name,
myClassTwo.Name);
}
);
break;
case "Increment":
myCurrentClass.Sort(delegate(MyClass myClassOne, MyClass myClassTwo)
{
return
Comparer<int>.Default.Compare(myClassOne.Increment,
myClassTwo.Increment);
});
break;
}
}
}
... but ideally I would like to switch on the underlying type of the Property (string, int etc.) and using a distinct number of delegate calls for the types for sorting. I've looked around but I've not found anything which points me in the right direction. I've had a look at reflection but I couldn't see anything which would be able to help me.
Is this even possible? and if so, how?!
Cheers!

Reflection would be the way to go - look at Type.GetProperty(string name). Creating the right comparer might be tricky after that - you might want to write a generic method, and then invoke that with reflection based on the property type. It all gets pretty icky, I'm afraid - but it's definitely feasible.

private void Sort( string propertyName )
{
List<MyClass> myCurClass = ...
myCurClass.Sort(delegate( MyClass left, MyClass right ){
PropertyInfo lp = typeof(MyClass).GetProperty (propertyName);
Comparer.Default.Compare (pi.GetValue(left), pi.GetValue(right));
});
}
I think this should get you started. :)
(Not tested, nor compiled, but you'll get the idea)

After hitting my head against the problem for a while and hoping on a train home last night I decided that I would try and bash out an answer. Using a combination of Jon's pointers and Frederik's use of the PropertyInfo class and keeping the original idea of switching on the underlying object type, this is what I came up with ...
private void Sort_version2(string propertyName)
{
// convert to list
List<MyClass> myCurrentClass = Items as List<MyClass>;
string typeOfProperty;
PropertyInfo pi;
// sort
if ((myCurrentClass != null) && (MyClass.HasDetailAndExtract(propertyName, out typeOfProperty, out pi)))
{
switch(typeOfProperty)
{
case "System.String":
myCurrentClass.Sort(delegate(MyClass one, MyClass two)
{
return
Comparer<string>.Default.Compare(pi.GetValue(one, null).ToString(),
pi.GetValue(two, null).ToString());
});
break;
case "System.Int32":
myCurrentClass.Sort(delegate (MyClass one, MyClass two)
{
return
Comparer<int>.Default.Compare(
Convert.ToInt32(pi.GetValue(one, null)),
Convert.ToInt32(pi.GetValue(two, null)));
});
break;
default:
throw new NotImplementedException("Type of property not implemented yet");
}
}
}
I've documented the thought process and more details on my blog let me know what you think!
Thanks to Jon and Frederik for the help :-)

Related

Modify fields in extraneous function

I have a lot of duplicate code places:
if (claimSettingHistoryDto.NewClaimTypeName == claimSettingHistoryDto.OldClaimTypeName)
{
claimSettingHistoryDto.NewClaimTypeName = null;
claimSettingHistoryDto.OldClaimTypeName = null;
}
if (claimSettingHistoryDto.NewApplicantName == claimSettingHistoryDto.OldApplicantName)
{
claimSettingHistoryDto.NewApplicantName = null;
claimSettingHistoryDto.OldApplicantName = null;
}
if (claimSettingHistoryDto.NewDamageSparePartsTotalCostInsertion == claimSettingHistoryDto.OldDamageSparePartsTotalCostInsertion)
{
claimSettingHistoryDto.NewDamageSparePartsTotalCostInsertion = null;
claimSettingHistoryDto.OldDamageSparePartsTotalCostInsertion = null;
}
and so constantly for different classes of different fields
I wish I had a feature like this:
private void SetNull(object newData, object oldData)
{
if (newData == oldData)
{
newData = null;
oldData = null;
}
}
but of course I understand that this is not true, since I only change the local value inside the function. How do I change the class field?
There are multiple ways of doing that, with varying positions on the "good idea" to "bad idea" spectrum.
Fields as ref parameters (good idea)
(...) this is not true, since I only change the local value inside the function
You're wrong, because ref and out parameters allow you to change values non-locally.
If you have access to the actual fields, you can pass them as a ref parameter:
public class Dto
{
private string? _old;
private string? _new;
public string? Old => _old;
public string? New => _new;
public void Foo() {
SetNullIfEqual(ref _new, ref _old);
}
private static void SetNullIfEqual<T>(ref T? newData, ref T? oldData) where T: class
{
if (newData == oldData)
{
newData = null;
oldData = null;
}
}
}
More info on passing as reference here.
This won't work with properties, even if they have a default setter. Properties are not fields, they're methods in disguise. If you can't access the actual fields...
Properties as delegates (meh idea)
... having access to properties only you'd need to pass them as delegates like this:
public class Dto
{
public string? Old { get; set; }
public string? New { get; set; }
}
public class Outside
{
public void Foo(Dto dto) {
SetNullIfEqual(() => dto.New, () => dto.Old, v => dto.New = v, v => dto.Old = v);
}
private static void SetNullIfEqual<T>(
Func<T?> getNew,
Func<T?> getOld,
Action<T?> setNew,
Action<T?> setOld) where T: class
{
if (getNew() == getOld())
{
setNew(null);
setOld(null);
}
}
}
This is clunky though, you have to question how much space it'd actually save. An instance method working on fields as in the first suggestion works much better.
When you have reflection everything looks like a nail (probably bad idea)
You can also do this with reflection, which will remove all safety, give much worse performance, but the absolute most flexibility.
using System.Reflection;
public class Dto
{
public string? Old { get; set; }
public string? New { get; set; }
}
public class Outside
{
public void Foo(Dto dto) {
SetNullIfEqual(nameof(dto.New), nameof(dto.Old), dto);
}
private static void SetNullIfEqual<T>(
string newPropName,
string oldPropName,
T instance)
{
PropertyInfo newProp = typeof(T).GetProperty(newPropName);
PropertyInfo oldProp = typeof(T).GetProperty(oldPropName);
if (Equals(newProp.GetValue(instance), oldProp.GetValue(instance)))
{
newProp.SetValue(instance, null);
oldProp.SetValue(instance, null);
}
}
}
I removed all error handling for brevity.
Recommendation
I'd go with the fields-as-ref-parameters way. If the method in question lives outside of the type, so it can't have access to the fields (don't ever use public fields please), I'd just move it into the type. In your case it'd be a bunch of methods called SetClaimTypeName, SetApplicantName, etc.

Updating an object from another objects property history in C# for implementing a PATCH

I'm trying to implement a PATCH on Web API for an object that will be stored in a DB. The input object from the controller has all of the properties that can be modified but we allow the client to choose which fields to send back. We only want to update the MongoDB representation if some of the fields have changed or been set. We started using a Dirty object pattern (not sure this is a pattern) whereby when you set a property you also record that it is dirty. for instance
public class Example
{
private string _title;
public string Title
{
get { return _title; }
set
{
_title = value;
TitleWasSet = true;
}
}
public bool TitleWasSet {get;set;}
}
This could work but is kind of tedious and I feel it exposes lots of logic that could be contained.
So a solution I came up with was to store the update Actions in the inbound object then reapply them to the Mongo Object in a Try Update fashion.
like this:
public class Data
{
public string Header { get; set; }
public int Rating { get; set; }
}
public class EditDataRequest
{
private readonly List<Action<Data>> _updates;
public EditDataRequest()
{
_updates = new List<Action<Data>>();
}
public string Header
{
set
{
_updates.Add(data => {data.Header = value;});
}
}
public int Rating
{
set
{
_updates.Add(data => {data.Rating = value;});
}
}
public bool TryUpdateFromMe(Data original)
{
if (_updates.Count == 0)
return false;
foreach (var update in _updates)
{
update.Invoke(original);
}
return true;
}
}
Now this would work great but it doesn't take account of the values being the same. So i then looked at changing the list of actions to a list of functions that would return a bool if there was a difference in the value.
private readonly List<Func<Data, bool>> _updates;
And then the properties would look like this:
public int Rating
{
set
{
_updates.Add(data => {
if (data.Rating != value)
{
data.Rating = value;
return true;
}
return false;
});
}
}
And the try update method...
public bool TryUpdateFromMe(Data original)
{
if (_updates.Count == 0)
return false;
bool changesRequired = false;
foreach (var update in _updates)
{
changesRequired |= update.Invoke(original);
}
return changesRequired;
}
As you can see that property set implementation is rather clunky and would make the code nasty to read.
I'd like a way of extracting the check this property value then update it to another method that I can reuse in each property - I assume this is possibly somehow but it might not be.
Of course, if you have better suggestions for how to handle the PATCH situation then I'd be happy to hear them as well.
Thanks for reading this far.

interconnected lists C#

I have class with two properties which are Lists, one of it contents int - that's IDs of objects from second List. I override setters and getters to save them agreeable with each other. But when I add some this to list they are not synchronized. How to make them synchronized?
Here is code
public class Item
{
private List<Operation> _operations = new List<Operation>();
private List<int> _operationsID = new List<int>();
public List<Operation> operations
{
get { return this._operations; }
set
{
this._operations = value;
if (value != null)
{
foreach (Operation oper in value)
{
this._operationsID.Add(oper.ID);
}
}
}
}
public List<int> operationsID
{
get { return this._operationsID; }
set
{
this._operationsID = value;
if (value != null)
{
foreach (int operID in value)
{
this._operations.Add(new Operation(operID));
}
}
}
}
}
Should I override List.Add if so, how it can me made?
It is a bit unclear what it is you are trying to do, but basically it seems like you need to encapsulate those lists so the user can't work on them directly (and get them out of sync). You do this by not exposing the lists to the user. Basically you are trying to keep the items contained to the user so whenever they work on your set of items, they would be forced to go through this class and the functions that class exposes. Your only issue then is to find out what to expose to the user and in what manner.
public class Item {
private List<Operation> _operations = new List<Operation>();
private List<int> _operationsID = new List<int>();
public void addOperation(Operation o) {
_operations.Add(o);
_operationsID.Add(getIdentifier(o));
}
public void removeOperation(Operation o) {
_operations.Remove(o);
_operationsID.Remove(getIdentifier(o));
}
public void clear() {
_operations.clear();
_operationsID.clear();
}
public void findOperationMatching(Foobar foo) {
//
}
private int getIdentifier(Operation id) {
//
}
}
You have to clear previous list content before calling Add method:
public List<Operation> operations
{
get { return this._operations; }
set
{
this._operations = value;
if (value != null)
{
this._operationsID.Clear();
foreach (Operation oper in value)
{
this._operationsID.Add(oper.ID);
}
}
else
{
this._operationsID = null;
}
}
}
But to be honest, I don't think it's a good idea to keep these things in two different lists. Why don't you use Dictionary<int, Operation>?
It's a bad idea to try to manage two versions of the truth. If it were me, I'd expose one List<Operation> that callers can Add/Remove, and a second IEnumerable<int> which simply exposes the ID's of the operations:
public List<Operation> Operations { get; set; }
public IEnumerable<int> OperationIDs
{
get
{
return Operations.Select(op => op.OperationID);
}
}
This way, callers can use the Operations list to do whatever they need to do (Add, Remove, Count, etc). The OperationIDs is now not a second property that people can work with; instead it only reflects information that is in the Operations property.

How to implement Lazy loading with PostSharp?

I would like to implement lazy loading on properties with PostSharp.
To make it short, instead of writing
SomeType _field = null;
private SomeType Field
{
get
{
if (_field == null)
{
_field = LongOperation();
}
return _field;
}
}
I would like to write
[LazyLoadAspect]
private object Field
{
get
{
return LongOperation();
}
}
So, I identify that I need to emit some code in the class to generate the backing field, as well as inside the getter method in order to implement the test.
With PostSharp, I was considering overriding CompileTimeInitialize, but I am missing the knowledge to get a handle over the compiled code.
EDIT:
The question can be extended to any parameterless method like:
SomeType _lazyLoadedField = null;
SomeType LazyLoadableMethod ()
{
if(_lazyLoadedField ==null)
{
// Long operations code...
_lazyLoadedField = someType;
}
return _lazyLoadedField ;
}
would become
[LazyLoad]
SomeType LazyLoadableMethod ()
{
// Long operations code...
return someType;
}
After our comments, I think I know what you want now.
[Serializable]
public class LazyLoadGetter : LocationInterceptionAspect, IInstanceScopedAspect
{
private object backing;
public override void OnGetValue(LocationInterceptionArgs args)
{
if (backing == null)
{
args.ProceedGetValue();
backing = args.Value;
}
args.Value = backing;
}
public object CreateInstance(AdviceArgs adviceArgs)
{
return this.MemberwiseClone();
}
public void RuntimeInitializeInstance()
{
}
}
Test code
public class test
{
[LazyLoadGetter]
public int MyProperty { get { return LongOperation(); } }
}
Thanks to DustinDavis's answer and comments, I could work on my own implementation, and I just wanted here to share it to help other people.
The main differences from the original answer are:
Implement the suggested "only run the operation once" (purpose of the lock)
Made the initialization status of the backing field more reliable by passing this responsibility to a boolean.
Here is the code:
[Serializable]
public class LazyLoadAttribute : LocationInterceptionAspect, IInstanceScopedAspect
{
// Concurrent accesses management
private readonly object _locker = new object();
// the backing field where the loaded value is stored the first time.
private object _backingField;
// More reliable than checking _backingField for null as the result of the loading could be null.
private bool _hasBeenLoaded = false;
public override void OnGetValue(LocationInterceptionArgs args)
{
if (_hasBeenLoaded)
{
// Job already done
args.Value = _backingField;
return;
}
lock (_locker)
{
// Once the lock passed, we must check if the aspect has been loaded meanwhile or not.
if (_hasBeenLoaded)
{
args.Value = _backingField;
return;
}
// First call to the getter => need to load it.
args.ProceedGetValue();
// Indicate that we Loaded it
_hasBeenLoaded = true;
// store the result.
_backingField = args.Value;
}
}
public object CreateInstance(AdviceArgs adviceArgs)
{
return MemberwiseClone();
}
public void RuntimeInitializeInstance() { }
}
I think the requirement cannot be accurately described as 'lazy loading', but is a special case of a more general caching aspect with in-AppDomain storage but without eviction. A general caching aspect would be able to handle method parameters.

Properties exposing array elements in C#

I want to create a property in C# that sets or returns an individual member of an array. Currently, I have this:
private string[] myProperty;
public string MyProperty[int idx]
{
get
{
if (myProperty == null)
myProperty = new String[2];
return myProperty[idx];
}
set
{
myProperty[idx] = value;
}
}
However, I get the following compile error:
Bad array declarator: To declare a managed array the rank specifier precedes the variable's identifier. To declare a fixed size buffer field, use the fixed keyword before the field type.
How about this: write a class that does one thing and one thing only: provide random access to elements of some underlying indexed collection. Give this class a this indexer.
For properties that you want to provide random access to, simply return an instance of this indexer class.
Trivial implementation:
public class Indexer<T>
{
private IList<T> _source;
public Indexer(IList<T> source)
{
_source = source;
}
public T this[int index]
{
get { return _source[index]; }
set { _source[index] = value; }
}
}
public static class IndexHelper
{
public static Indexer<T> GetIndexer<T>(this IList<T> indexedCollection)
{
// could cache this result for a performance improvement,
// if appropriate
return new Indexer<T>(indexedCollection);
}
}
Refactoring into your code:
private string[] myProperty;
public Indexer<string> MyProperty
{
get
{
return myProperty.GetIndexer();
}
}
This will allow you to have as many indexed properties as you want, without needing to expose those properties with the IList<T> interface.
You must use this as the property name for indexers.
C# allows only one indexed property per class, so you are forced to use this.
You can use it this way:
private string[] myProp;
public string[] MyProp
{
get
{
if (myProp == null)
{
myProp = new String[2];
}
return myProp;
}
set
{
myProp = value;
}
}
And it's possible to acces myProp[1] as MyProp[1] for Example
Exposing your array through a read-only property might cover your needs. Since you don't want to allow other code to assign the array as such, there is no need for a public setter:
private string[] myProperty;
public string[] MyProperty
{
get
{
if (myProperty == null)
{
myProperty = new String[2];
}
return myProperty;
}
}
Then you can write code as such:
theObject.MyProperty[1] = "some string";
...but you cannot replace the array itself:
theObject.MyProperty = new string[2]; // will not compile
An option is to recode it as follows:
private string[] myProperty = new string[2];
public string[] MyProperty
{
get
{
return myProperty;
}
set
{
myProperty = value;
}
}
It'll compile, but it does have its own set of issues (fxCop will yell about it, but it can lead you to other options).
You could do something like this:
class Indexers
{
private string[] _strings = new [] {"A","B"};
private int[] _ints = new[] { 1, 2 };
public string[] Strings
{
get{ return _strings;}
}
public int[] Ints
{
get{ return _ints;}
}
}
class Program
{
static void Main(string[] args)
{
Indexers indexers = new Indexers();
int a1 = indexers.Ints[0];
string a2 = indexers.Strings[0];
}
}
C# provides no built-in mechanism to create indexed properties. You can use a class-level indexer (using this[int index] notation), but nothing like this on a property level.
One option is to create a helper class with an indexer and use this class as the property type. See an example on MSDN.
First, in-field declaration avoids excess check:
private string[] myProperty = new string[2];
You can implement several indexers via overloading by input type:
public string this[int index]
{
get
{
return myProperty[index];
}
set
{
myProperty[index] = value;
}
}
public object this[object a, object b] // different input type(s) (and different return type)
{
get
{
// do other stuff
}
}
You need to use an indexer. It works a little differently. See example:
public class Node
{
public Node this[int offset]
{
get { return localList[offset]; }
}
}
Note: You are allowed only one indexer per class. The reason is that it is too confusing to the compiler as to the meaning, so you only are allowed one.
You can also do this:
private static int[] _widget = new int[Counter];
public static int [] Widget
{
get { return _widget; }
set { _widget = value; }
}
...
for (int i = 0; i < MyClass.Counter; i++)
{
MyClass.Widget[i] = i;
}
...
double _newWidget5 = MyClass.Widget[5];
// and so on...

Categories