We currently have code in place for resolving internal references within a json file. For exmaple:
public class AnswerHolder
{
public int Answer { get; set; }
}
public class EverythingHolder
{
public string Everything { get; set; }
}
public class Container
{
public AnswerHolder The { get; set; }
public EverythingHolder Question { get; set; }
}
{
"The": {
"Answer": 42
},
"Question": {
"Everything": "The answer is: {The.Answer}"
}
}
Here's the relatively simple code that traverses the instance
, in this case, the entire json object. This code only works for property accesses. Another piece of code searches string values and identifies properties with placeholders and extracts the placeholder's value. We call these placeholders "property strings". The below function is called with the propertyString="The.Answer"
and the instance
of Container
. This function simply splits the property string on dot accessors and iteratively walks down the object graph.
public object Evaluate(object instance, string propertyString)
{
if (string.IsNullOrEmpty(propertyString))
{
return instance;
}
if (string.IsNullOrWhiteSpace(propertyString))
{
throw new ArgumentException("Property string must not be white space.");
}
var instanceType = instance.GetType();
var current = instance;
var type = instanceType;
var properties = propertyString.Split('.');
foreach (var property in properties)
{
var propertyInfo = type.GetProperty(property, bindingFlags);
if (propertyInfo == null)
{
throw new Exception($"Invalid property string for type '{instanceType.FullName}': " +
$"'{propertyString}'.Unable to resolve property '{property}' on type '{type.FullName}"
);
}
current = propertyInfo.GetValue(current);
type = current.GetType();
}
return current;
}
What I'd like to do is add support for indexers, such as dictionary indexers and array/list indexers. Now, I could go about this in the same way by first checking the property string for square brackets and recursively resolving them from the outside in to ensure proper order of evaluation, but this got me thinking, would it be simpler and far more flexible, to wrap it in a function accepting the instance
as a parameter and just compile it w/ Roslyn? This would remove the parsing logic which is great for maintainability because we all know next year it'll be, oh can we a xyz. Also, supporting C# would open us up to mathematical operations, allowing for better readability, for example, writing 3.5 * 60 * 60
for 3.5 hours in seconds instead of just a value and a (hopefully) accompanying comment.
question from:
https://stackoverflow.com/questions/65898798/turing-complete-variable-substitution-in-text-files-via-roslyn 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…