My idea is to store text with string.Format() place holders {0}...{n} in a database. The place holder value types are stored in another database field called "Parameters" in a comma separated format (CSV).
An example of a text in a database:
Sender: {0}
Address: {1}Receiver: {2}
Address: {3}
And the "Parameters" field contains:
Company.FullName, Company.Address.FullAddress, Customer.Full开发者_运维百科Name, Customer.Address.FullAddress
I hope it is obvious that the "Company", "Customer" and "Address" represent classes. FullName and FullAddress reperesent properties that return a string. The "Company" and "Customer" objects are able to load correct Address on request.
I am considering to use "params object[] params" with the string.Format() to pass the values.
Now the question is how to load the correct objects and pass matching count of params to the string.Format method?
Requirements
- The text in a database must be editable;
- The place holder count might be changed (added or removed);
- Each place holder has corresponding parameter in "Parameters" database field;
- Each parameter represents a class name and its property. Subclasses could be called but they must be separated by a dot (.). Example: Company.Address.FullAddress;
- Only required object(s) specific to the text in the database should be created or loaded. It is not a good idea to load bunch of object just in case;
- It would be great if just one method could handle the task;
- Use any pattern or patterns if there is any suitable one. Maybe the Composite, Factory or the Builder pattern perhaps?
As a solution I see:
- Hard code the object(s) loading for each database record. This requires that the text with place holders cannot be changed. So this solution is not suitable for me.
- Load the object(s) using reflections per parameter. This would be a good dynamic way to do it but how to load correct "Address" object with the Customer address info it? Customer object is created/loaded by its CustomerId.
So far I am this far:
public string FillTemplate(int languageId, long templateTypeId, params object[] parameters)
{
string formatStringFromDb = LoadTemplateContentFromDb(languageId, templateTypeId);
return string.Format(formatStringFromDb, parameters);
}
public object[] LoadTemplateParameter(int languageId, long templateTypeId)
{
string csvTemplateParameters = LoadTemplateParametersFromDb(languageId, templateTypeId);
string[] stringParameters = csvTemplateParameters.Split(',');
object[] templateParametersToReturn = new object[stringParameters.Length];
for (int i = 0; i < stringParameters.Length; i++)
{
// Split class name(s) and property
string[] classAndPropertyNames = stringParameters[i].Split('.');
// Initialise and add the object to the parameter object array
templateParametersToReturn[i] = InitialiseParameterObject(classAndPropertyNames);
}
return templateParametersToReturn;
}
private static object InitialiseParameterObject(string[] classAndPropertyNames)
{
// Now what? How do I create new object(s) from a string?
// To create a Customer or Company class an appropriate ID is needed.
// How do I know which ID (Customer or Company)
// do I need to provide in advance?
throw new NotImplementedException();
}
Thank you if could read this far. Even better if you got some ideas for me :)
PS. At the moment LoadTemplateContentFromDb and LoadTemplateParametersFromDb make two separate calls to the database but I will refactor it so that a whole template info is asked at once.
Once you have the object, and a string for it's properties, these methods i wrote for something else could help:
/// <summary>
/// Gets an object property's value, recursively traversing it's properties if needed.
/// </summary>
/// <param name="FrameObject">The object.</param>
/// <param name="PropertyString">The object property string.
/// Can be the property of a property. e.g. Position.X</param>
/// <returns>The value of this object's property.</returns>
private object GetObjectPropertyValue(Object FrameObject, string PropertyString)
{
object Result = FrameObject;
string[] Properties = PropertyString.Split('.');
foreach (var Property in Properties)
{
Result = Result.GetType().GetProperty(Property).GetValue(Result, null);
}
return Result;
}
public Type GetObjectPropertyType(string ObjectName, string PropertyString)
{
Object Result = GetObjectByName(ObjectName);
string[] Properties = PropertyString.Split('.');
foreach (var Property in Properties)
{
Result = Result.GetType().GetProperty(Property).GetValue(Result, null);
}
return Result.GetType();
}
For getting it into string.Format()
you could use the above methods to go from an array of property strings, to the properties themselves. You'd then pass this as the final argument os string.Format()
.
精彩评论