Using ConcurrentDictionary as a cache and handling update - c#

I have the below code and now I want to add an UpdateSetting method.
The best way of doing this that I can see is via TryUpdate on the ConcurrentDictionary but that means knowing the previous value so that would require a call to GetSetting which seems a bit yucky. What are your thoughts? Is there a better way?
NOTE: If the value is not in the cache it should do nothing. On successful updating of cache it should call the settingRepository.Update
Thanks
public class MySettings : IMySettings
{
private readonly ISettingRepository settingRepository;
private readonly ConcurrentDictionary<string, object> cachedValues = new ConcurrentDictionary<string, object>();
public MySettings(ISettingRepository settingRepository)
{
this.settingRepository = settingRepository;
}
public string GetSetting(string key)
{
return this.GetSetting<string>(key);
}
public T GetSetting<T>(string key)
{
object value;
if (!this.cachedValues.TryGetValue(key, out value))
{
value = this.GetValueFromRepository(key, typeof(T));
this.cachedValues.TryAdd(key, value);
}
return (T)value;
}
private object GetValueFromRepository(string key, Type type)
{
var stringValue = this.settingRepository.GetSetting(key);
if (stringValue == null)
{
throw new MissingSettingException(string.Format("A setting with the key '{0}' does not exist.", key));
}
if (type == typeof(string))
{
return stringValue;
}
return ConvertValue(stringValue, type);
}
private static object ConvertValue(string stringValue, Type type)
{
return TypeDescriptor.GetConverter(type).ConvertFromString(stringValue);
}
}

Might be worth getting the existing value to possible avoid updating the repository. And an exception if more expensive than a try
public bool UpdateSetting<T>(string key, T value)
{
lock
{
T oldValue;
if (this.cachedValues.TryGetValue(key, out oldValue)
{
if (oldValue != value)
{
this.cachedValues[key] = value;
settingRepository.Update(key, value);
}
return true;
}
else
{
return false;
}
}
}

One way would be to simply set the value, and catch the exception that it will throw if the key is not in the collection.
public bool UpdateSetting<T>(string key, T value)
{
try {
this.cachedValues[key] = value;
} catch (KeyNotFoundException ex) {
return false;
}
return true;
}
Whether this is how you want to handle the key not existing is up to you. But if you decide you want to add the key, then you should use the AddOrUpdate method rather than the simple assignment above. And you won't need to catch that exception in that case.
To address the bigger issue of your backing repository, I think you'll need something along the lines of this.
public bool UpdateSetting<T>(string key, T value)
{
lock {
try {
this.cachedValues[key] = value;
this.settingRepository.Update(... //you'll have to write this
} catch (KeyNotFoundException ex) {
return false;
}
return true;
}
}
I don't think you can avoid the use of a lock to ensure the change to the cache matches the repository. For the same reason, I think some of your existing code may need locking as well. Using ConcurrentDictionary only protects you in the operations on the dictionary. But in the larger scope, there is more going on that needs synchronization.

Related

WPF c# DynamicObject. how to enforce type checking on the added properties?

I define a DynamicObject.
I have created a list of DynamicObjects with the same structure and link them to a WPF GridView.
I allow editing of some of the properties via the grid.
As the DynamicObjects present the property data as objects, how can I enforce Type restrictions?
if the user types alphabet into a cell that I would like as an int how can I get the DynamicObject to refuse the input?
You could use a TryParse wherever you're taking the cell input:
int result;
if(int.TryParse(cellText, out result))
{
// Is an integer
}
else
{
}
bool and other value types also have a TryParse if you're taking those values as well.
See also:
Comparing Types in this question
The DynamicDictionary example in the docs for a more verbose implementation on adding and editing properties.
In the constructor of my DynamicObject, I pass in with the properties definition, a dictionary of the types.
I then override the TrySetMember method to convert the value from the string supplied by the grid into its required type.
The issue I now have is sending a error message back to the grid if the conversion fails.
Here is My DynamicObject definition:
public sealed class FwDynamicObject : DynamicObject
{
private readonly Dictionary<string, object> _properties;
private readonly Dictionary<string, Type> _propertyTypes;
public FwDynamicObject(Dictionary<string, object> properties, Dictionary<string, Type> propertyTypes = null)
{
_properties = properties;
_propertyTypes = propertyTypes;
}
public override IEnumerable<string> GetDynamicMemberNames()
{
return _properties.Keys;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (_properties.ContainsKey(binder.Name))
{
result = _properties[binder.Name];
return true;
}
else
{
result = null;
return false;
}
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if (_properties.ContainsKey(binder.Name))
{
var t = GetMemberType(binder.Name);
if (t != null)
{
try
{
value = Convert.ChangeType(value, t);
}
catch(Exception e)
{
return false;
}
}
_properties[binder.Name] = value;
return true;
}
else
{
return false;
}
}
private Type GetMemberType(string name)
{
if (_propertyTypes.ContainsKey(name))
{
return _propertyTypes[name];
}
return null;
}
}

Shorten syntax for nearly identical properties

I have to rework some code and stumbled upon a few classes which define a huge amount of very similar properties.
They look something like this:
public _ReturnType _PropertyName
{
get
{
IMarkerInterface value = null;
if (Properties != null) Properties.TryGetValue(_string, out value);
return value as _ReturnType;
}
set { Properties[_string] = value; }
}
The only difference between them is the _ReturnType, the _string that is used in the dictionary Properties and obviously the _PropertyName.
I was wondering if there is a way to shorten the syntax?
If you see duplicate code, you extract a method. It would look something like this:
private T GetValueOrDefault<T>(string key)
{
IMarkerInterface value = null;
if (Properties != null) Properties.TryGetValue(key, out value);
return value as T;
}
Then change your getter:
get
{
return GetValueOrDefault<_ReturnType>("key");
}
But if this code is spread out over multiple classes, you'd have to define a base class containing the Properties property and the above GetValueOrDefault() method, albeit protected instead of private.
Alternatively, you'd define it as an extension method on whatever the type of Properties is:
public static T GetValueOrDefault<T>(this IDictionary<string, IMarkerInterface> properties, string key)
{
IMarkerInterface value = null;
if (properties != null) properties.TryGetValue(key, out value);
return value as T;
}
And call it as such:
get
{
return Properties.GetValueOrDefault<_ReturnType>("key");
}
But, as #Daniel comments, this smells like an ideal scenario for code generation, because without that you'd still have a couple of lines of (copy-pasted, error-prone) code.
There probably is a source somewhere for what these properties should be named, and you can use something like T4 templates to generate this code file from it.
Well, you could do this:
private IMarkerInterface getIMF(string str)
{
IMarkerInterface value = null;
Properties?.TryGetValue(_string, out value);
return value;
}
public _ReturnType _PropertyName
{
get { return getIMF(_string) as _ReturnType; }
set { Properties[_string] = value; }
}
If Properties implements IReadOnlyDictionary<string, object> (like a Dictionary<string, object> for instance), one thing you could do is add an extension method:
public static TValue TryGetValue<TValue>(
this IReadOnlyDictionary<string, object> properties,
string key)
where TValue : class
{
if ((properties != null) &&
properties.TryGetValue(key, out object value))
{
return value as TValue;
}
return null;
}
and then
public IMarkerInterface MarkerInterface
{
get => Properties.TryGetValue<IMarkerInterface>("MarkerInterface");
set { Properties["MarkerInterface"] = value; }
}
Link to Fiddle

Check Dictionary.Add() key uniqueness at compile time

Is there a way to check at compile time a dictionary's key uniqueness in a method scope when you add them with the Add() method?
Example: there are a bunch of payment solution providers (PayPal, PayEx, etc.) that give some sort of a status result when you query a transaction, lets say an integer. Since every PSP handles statuses differently, we have a fixed amount of system statuses (such as Pending, Aborted, Committed, etc.) that are mapped to the various status codes for each PSP.
public static class ResponseMapping
{
private static readonly Dictionary<int, PaymentResult> ResultMap;
static ResponseMapping()
{
ResultMap = new Dictionary<int, PaymentResult>();
ResultMap.Add(1, PaymentResult.LogonError);
ResultMap.Add(2, PaymentResult.Pending);
ResultMap.Add(9, PaymentResult.Ok);
// OH DEAR, THIS WILL BLOW UP
ResultMap.Add(1, PaymentResult.Something);
}
public static PaymentResult FindAppropriateResponse(int resultCode)
{
if (ResultMap.ContainsKey(resultCode))
{
return ResultMap[resultCode];
}
return PaymentResult.UnknownResult;
}
}
An easy shortcut would be to use the [] indexing notation to add each map, but with Add() you can avoid possibly overriding something that you didn't mean to.
Unfortunately, this way it blows up at runtime. Is there a technique that would make it blow up at compile time?
I don't think you can check for key existence at compile time. Instead you can use Dictionary.ContainsKey method like:
int key = 1; //your key
if(!ResultMap.ContainsKey(key))
{
ResultMap.Add(key, PaymentResult.Something);
}
You can use ContainsKey:
if(!ResultMap.ContainsKey(1))
{
ResultMap.Add(1, PaymentResult.Something);
}
or TryGetValue:
obj item;
if(!ResultMap.TryGetValue(1, out item))
ResultMap.Add(1, PaymentResult.Something);
If you really really need a dictionary object I don't think you can do it at compile time and can sort of fake it with a unit test. But if you just want a look up, use a switch.
public static PaymentResult FindAppropriateResponse(int resultCode)
{
switch(resultCode)
{
case 1:
return PaymentResult.LogonError;
case 2:
return PaymentResult.Pending;
case 3:
return PaymentResult.Ok;
default:
return PaymentResult.UnknownResult;
case 1: // Does blow up at compile time
return PaymentResult.Something;
}
}
You could define a method which you use instead of Add.
It will add the value if not exists or replace it if it exists.
private void Add(Dictionary<int, PaymentResult> PaymentResults, int index, PaymentResult pResult)
{
if(PaymentResults.ContainsKey(index))
{
PaymentResults[index] = pResult;
}
else
{
PaymentResults.Add(index, pResult);
}
}
And to use it
this.Add(ResultMap, 1, PaymentResult.LogonError);
This is related but not exactly. I had the problem of I wasn't sure if a key would exist or not, so I created a simple method.
private void AddKey(string key, string value)
{
if (!Dictionary.ContainsKey(key))
Dictionary.Add(key, value);
}
The just call AddKey(key,value);
Maybe this will help you some.
Or extend
public static class Extensions
{
public static bool Push<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue value)
{
try
{
if (dictionary.ContainsKey(key))
{
dictionary[key] = value;
}
else
{
dictionary.Add(key, value);
}
return true;
}
catch (Exception ex)
{
return false;
}
}
public static TValue Pull<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key)
{
try
{
return dictionary.ContainsKey(key) ? dictionary[key] : default(TValue);
}
catch (Exception ex)
{
return default(TValue);
}
}
}
Then you can do
ResultMap = new Dictionary<int, PaymentResult>();
ResultMap.Push(1, PaymentResult.LogonError); //1 -> PaymentResult.LogonError
ResultMap.Push(1, PaymentResult.Something); //1 -> PaymentResult.Something

Using Attributes to simplify properties

I have a scenario where I need the properties in my class to map to a dictionary. Here is a code sample:
public string Foo
{
get
{
if (!PropertyBag.ContainsKey("Foo"))
{
return null;
}
return PropertyBag["Foo"];
}
set
{
PropertyBag["Foo"] = value;
}
}
I have to apply this pattern to multiple properties. Is there a way to use attributes to do that?
I know that PostSharp would work for this purpose, but I was hoping there is a way to do it without using it.
This feels like a code smell to me. It would be better to use regular POCOs and convert them to a Dictionary only when needed.
public class BlogPost
{
public string Title { get; set; }
public string Body { get; set; }
public int AuthorId { get; set; }
public Dictionary<string, object> ToDictionary()
{
return this.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.ToDictionary(prop => prop.Name, prop => prop.GetValue(this, null));
}
}
Inspiration: How to convert class into Dictionary?
And to be honest, a ToDictionary method on your POCO's seems like a code smell. It would be better to refactor your code so the conversion of POCOs to Dictionaries happens in its own layer, as a service maybe.
Edit: This Gist I found while searching google for "c# convert object to dictionary" could provide a more generalized solution, and probably more bullet proof than my cobbled together example:
Gist: https://gist.github.com/jarrettmeyer/798667
From the Gist:
public static class ObjectToDictionaryHelper
{
public static IDictionary<string, object> ToDictionary(this object source)
{
return source.ToDictionary<object>();
}
public static IDictionary<string, T> ToDictionary<T>(this object source)
{
if (source == null)
ThrowExceptionWhenSourceArgumentIsNull();
var dictionary = new Dictionary<string, T>();
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(source))
AddPropertyToDictionary<T>(property, source, dictionary);
return dictionary;
}
private static void AddPropertyToDictionary<T>(PropertyDescriptor property, object source, Dictionary<string, T> dictionary)
{
object value = property.GetValue(source);
if (IsOfType<T>(value))
dictionary.add(property.Name, (T)value);
}
private static bool IsOfType<T>(object value)
{
return value is T;
}
private static void ThrowExceptionWhenSourceArgumentIsNull()
{
throw new ArgumentNullException("source", "Unable to convert object to a dictionary. The source object is null.");
}
}
Credit: jerrettmeyer at GitHub
This should add a ToDictionary method to every object.
Edit: From the following comment
To give a bit of context, I am using Entity Framework and I have a class hierarchy that I would like to keep in one table while avoiding null columns everywhere.
Entity framework supports multiple table inheritance. That might be a better solution in your case.
You can write a GetValueOrDefault extension method and reduce the code a little.
public static class DictionaryExtensions
{
public static TValue GetValueOrDefault<TKey, TValue>(this IDictionary<TKey,TValue> self, TKey key)
{
TValue value;
self.TryGetValue(key,out value);
return value;
}
}
public string Foo
{
get
{
return PropertyBag.GetValueOrDefault("Foo");
}
set
{
PropertyBag["Foo"] = value;
}
}
You can eliminate the magic strings using expressions.
If you're using at least .NET 4.5 then you have the CallerMemberNameAttribute which you could use like this:
class SomeClass
{
public string Foo
{
get
{
return GetPropertyValue();
}
set
{
SetPropertyValue( value );
}
}
private string GetPropertyValue( [CallerMemberName] string name = null )
{
string value;
PropertyBag.TryGetValue( name, out value );
return value;
}
private void SetPropertyValue( string value, [CallerMemberName] string name = null )
{
PropertyBag[name] = value;
}
}
This will result in the compiler filling out the name of the member for you. If you're not (or otherwise can't) use .NET 4.5, another alternative would be to take advantage of expression trees as suggested in another answer.
class Test
{
Dictionary<string,object> _values = new Dictionary<string, object>();
public string Foo
{
get
{
var value = GetValue();
return value == null ? string.Empty : (string)value;
}
set
{
SetValue(value);
}
}
private object GetValue()
{
var stack = new StackTrace();
var key = GetGenericName(stack.GetFrame(1).GetMethod().Name);
if (_values.ContainsKey(key)) return _values[key];
return null;
}
private void SetValue(object value)
{
var stack = new StackTrace();
var key = GetGenericName(stack.GetFrame(1).GetMethod().Name);
_values[key] = value;
}
private string GetGenericName(string key)
{
return key.Split('_')[1];
}
}

How can I refactor the mother of all C# Switch Statements

I am trying to refactor the mother of all switches and am not really sure how to do it. Here is the existing code:
bool FieldSave(Claim claim, string field, string value)
{
//out vars for tryparses
decimal outDec;
int outInt;
bool outBool;
DateTime outDT;
//our return value
bool FieldWasSaved = true;
//World Greatest Switch - God help us all.
switch (field)
{
case "Loan.FhaCaseNumber":
GetLoan(claim).FhaCaseNumber = value;
break;
case "Loan.FhaInsurance":
if (bool.TryParse(value, out outBool))
{
GetLoan(claim).FhaInsurance = outBool;
FieldWasSaved = true;
}
break;
case "Loan.UnpaidPrincipalBalance":
if (decimal.TryParse(value, out outDec))
{
GetLoan(claim).UnpaidPrincipalBalance = outDec;
FieldWasSaved = true;
}
break;
case "Loan.Mortgagor_MortgagorID":
if(Int32.TryParse(value, out outInt)){
GetLoan(claim).Mortgagor_MortgagorID = outInt;
FieldWasSaved = true;
}
break;
case "Loan.SystemDefaultDate":
if (DateTime.TryParse(value, out outDT))
{
GetLoan(claim).SystemDefaultDate = outDT;
FieldWasSaved = true;
}
break;
//And so on for 5 billion more cases
}
db.SaveChanges();
return FieldWasSaved;
}
Is there anyway to do this in a generic way or is this super switch actually necessary?
A BIT MORE CONTEXT
I don't claim to understand all the magic the other dev is up to, but basically the string "Loan.FieldName" is coming from some metadata tagged on to an HTML input tag. This is used in this switch to link a particular field to an entity framework data table / property combo. Although this is coming from a strongly typed view, for reasons beyond the ken of man this mapping has become the glue holding the whole thing together.
Usually when I refactor, it's to reduce the complexity of the code somehow, or make it easier to understand. In the code you posted, I have to say it doesn't seem all that complex (although there might be a lot of lines, it looks pretty repetitive and straight-forward). So other than the code aesthetics, I'm not sure how much you are going to gain by refactoring a switch.
Having said that, I might be tempted to create a dictionary where they key is field and the value is a delegate which contains the code for each case (each method would probably return a bool with the FieldWasSaved value, and would have some out-params for those 4 other values). Then your method would just use field to look up the delegate from the dictionary and then call it.
Of course, I would probably just leave the code as-is. The dictionary approach might not be as obvious to other devs, and probably makes the code less obvious to understand.
Update: I also agree with nightwatch that the best refactor will probably involve code which is not shown -- perhaps a lot of this code belongs in other classes (maybe there would be a Loan class which encapsulates all the Loan fields, or something like that...).
If the names in the case statement match with properties in the class, I would change it all to use reflection.
For example, here is a trimmed down version of the core of our base business record, which we use to move data in and out of databases, forms, web services, etc.
public static void SetFieldValue(object oRecord, string sName, object oValue)
{
PropertyInfo theProperty = null;
FieldInfo theField = null;
System.Type oType = null;
try
{
oType = oRecord.GetType();
// See if the column is a property in the record
theProperty = oType.GetProperty(sName, BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Public, null, null, new Type[0], null);
if (theProperty == null)
{
theField = oType.GetField(sName, BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Public);
if (theField != null)
{
theField.SetValue(oRecord, Global.ValueFromDB(oValue, theField.FieldType.Name));
}
}
else
{
if (theProperty.CanWrite)
{
theProperty.SetValue(oRecord, Global.ValueFromDB(oValue, theProperty.PropertyType.Name), null);
}
}
}
catch (Exception theException)
{
// Do something useful here
}
}
In the above, Global.ValueFromDB is a big switch statement that safely converts the value to the specified type. Here is a partial version of that:
public static object ValueFromDB(object oValue, string sTypeName)
{
switch (sTypeName.ToLower())
{
case "string":
case "system.string":
return StrFromDB(oValue);
case "boolean":
case "system.boolean":
return BoolFromDB(oValue);
case "int16":
case "system.int16":
return IntFromDB(oValue);
case "int32":
case "system.int32":
return IntFromDB(oValue);
Where the datatype specific FromDBs look something like:
public static string StrFromDB(object theValue)
{
return StrFromDB(theValue, "");
}
public static string StrFromDB(object theValue, string sDefaultValue)
{
if ((theValue != DBNull.Value) && (theValue != null))
{
return theValue.ToString();
}
else
{
return sDefaultValue;
}
}
public static bool BoolFromDB(object theValue)
{
return BoolFromDB(theValue, false);
}
public static bool BoolFromDB(object theValue, bool fDefaultValue)
{
if (!(string.IsNullOrEmpty(StrFromDB(theValue))))
{
return Convert.ToBoolean(theValue);
}
else
{
return fDefaultValue;
}
}
public static int IntFromDB(object theValue)
{
return IntFromDB(theValue, 0);
}
public static int IntFromDB(object theValue, int wDefaultValue)
{
if ((theValue != DBNull.Value) && (theValue != null) && IsNumeric(theValue))
{
return Convert.ToInt32(theValue);
}
else
{
return wDefaultValue;
}
}
It may not seem like your saving much code in the short term, but you will find many, many uses for this once it is implemented (we certainly have).
I know it is gosh to answer your own question, but here is how my boss solved this problem using reflection and a dictionary. I ironically, he finished his solution just minutes after we finished the "Mother of All Switches". No one wants to see an afternoon of typing rendered pointless, but this solution is a lot more slick.
public JsonResult SaveField(int claimId, string field, string value)
{
try
{
var claim = db.Claims.Where(c => c.ClaimID == claimId).SingleOrDefault();
if (claim != null)
{
if(FieldSave(claim, field, value))
return Json(new DataProcessingResult { Success = true, Message = "" });
else
return Json(new DataProcessingResult { Success = false, Message = "Save Failed - Could not parse " + field });
}
else
return Json(new DataProcessingResult { Success = false, Message = "Claim not found" });
}
catch (Exception e)
{
//TODO Make this better
return Json(new DataProcessingResult { Success = false, Message = "Save Failed" });
}
}
bool FieldSave(Claim claim, string field, string value)
{
//our return value
bool FieldWasSaved = true;
string[] path = field.Split('.');
var subObject = GetMethods[path[0]](this, claim);
var secondParams = path[1];
PropertyInfo propertyInfo = subObject.GetType().GetProperty(secondParams);
if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
FieldWasSaved = SetValue[Nullable.GetUnderlyingType(propertyInfo.PropertyType)](propertyInfo, subObject, value);
}
else
{
FieldWasSaved = SetValue[propertyInfo.PropertyType](propertyInfo, subObject, value);
}
db.SaveChanges();
return FieldWasSaved;
}
// these are used for dynamically setting the value of the field passed in to save field
// Add the object look up function here.
static Dictionary<string, Func<dynamic, dynamic, dynamic>> GetMethods = new Dictionary<string, Func<dynamic, dynamic, dynamic>>()
{
{ "Loan", new Func<dynamic, dynamic, dynamic>((x, z)=> x.GetLoan(z)) },
// and so on for the 15 or 20 model classes we have
};
// This converts the string value comming to the correct data type and
// saves the value in the object
public delegate bool ConvertString(PropertyInfo prop, dynamic dynObj, string val);
static Dictionary<Type, ConvertString> SetValue = new Dictionary<Type, ConvertString>()
{
{ typeof(String), delegate(PropertyInfo prop, dynamic dynObj, string val)
{
if(prop.PropertyType == typeof(string))
{
prop.SetValue(dynObj, val, null);
return true;
}
return false;
}
},
{ typeof(Boolean), delegate(PropertyInfo prop, dynamic dynObj, string val)
{
bool outBool = false;
if (Boolean.TryParse(val, out outBool))
{
prop.SetValue(dynObj, outBool, null);
return outBool;
}
return false;
}
},
{ typeof(decimal), delegate(PropertyInfo prop, dynamic dynObj, string val)
{
decimal outVal;
if (decimal.TryParse(val, out outVal))
{
prop.SetValue(dynObj, outVal, null);
return true;
}
return false;
}
},
{ typeof(DateTime), delegate(PropertyInfo prop, dynamic dynObj, string val)
{
DateTime outVal;
if (DateTime.TryParse(val, out outVal))
{
prop.SetValue(dynObj, outVal, null);
return true;
}
return false;
}
},
};
One possibility is to create a Dictionary that has the field name as the key, and a delegate as the value. Something like:
delegate bool FieldSaveDelegate(Claim claim, string value);
You can then write separate methods for each field:
bool SystemDefaultDateHandler(Claim cliaim, string value)
{
// do stuff here
}
And to initialize it:
FieldSaveDispatchTable = new Dictionary<string, FieldSaveDelegate>()
{
{ "Loan.SystemDefaultDate", SystemDefaultDateHandler },
// etc, for five billion more fields
}
The dispatcher, then:
FieldSaveDelegate dlgt;
if (!FieldSaveDispatchTable.TryGetValue(fieldName, out dlgt))
{
// ERROR: no entry for that field
}
dlgt(claim, value);
This would probably be more maintainable than the switch statement, but it's still not especially pretty. The nice thing is that the code to populate the dictionary could be automatically generated.
As a previous answer said, you can use reflection to look up the field name to ensure that it's valid, and check the type (also with reflection). That would reduce the number of handler methods you write to just a handful: one for each individual type.
Even if you didn't use reflection, you could reduce the number of methods required by saving the type, rather than the delegate, in the dictionary. Then you'd have a lookup to get the type for a field, and a small switch statement on the type.
That assumes, of course, that you don't do any special per-field processing. If you have to do special validation or additional processing on some fields, then you'll either need the one method per field, or you'll need some additional per-field information.
Depending on your application, you might be able to redefine Claim to be a dynamic object:
class Claim : DynamicObject
{
... // Current definition
public override bool TrySetMember(SetMemberBinder binder, object value)
{
try
{
var property = typeof(Loan).GetProperty(binder.Name);
object param = null;
// Find some way to parse the string into a value of appropriate type:
// (This will of course need to be improved to handle more types)
if (property.PropertyType == typeof(Int32) )
{
param = Int32.Parse(value.ToString());
}
// Set property in the corresponding Loan object
property.SetValue(GetLoan(this), param, null);
db.Save();
}
catch
{
return base.TrySetMember(binder, value);
}
return true;
}
}
If this is possible, you should be able to use the following syntax to work indirectly with the corresponding Loan objects through a Claim object:
dynamic claim = new Claim();
// Set GetLoan(claim).Mortgagor_MortgagorID to 1723 and call db.Save():
claim.Mortgagor_MortgagorID = "1723";
For the failed cases, when the input string can't be parsed, you will unfortunately get a RuntimeBinderException rather than a nice function return value, so you need to consider if this will be a good fit for you case.

Categories

Resources