How can I find previous usages of a variable using Roslyn? - c#

I'm writing a Rosyln analyser/analyzer. It checks to ensure that a method is called before accessing another (potentially dangerous) method on a type. To show what I mean, here's some bad code that I want to analyse and fail on:
private void myMethod()
{
var myThing = new MyThing();
myThing.Value = null;
string value = myThing.GetValue(); // code blows up here as the internal value is null
}
Here's code that's OK because it calls a method that says whether it's null:
private void myMethod()
{
var myThing = new MyThing();
myThing.Value = null;
if(!myThing.HasValue)
{
return ;
}
string value = myThing.GetValue();
}
So, it should check that all calls to GetValue are preceeded by a call to HasValue.
I've just started with Roslyn, so there's probably a more elegant way than my initial (failing) attempt at:
1 - Declare that I want to inspect invocation expressions
context.RegisterSyntaxNodeAction(analyseMemberAccessNode, SyntaxKind.InvocationExpression);
2 - In my method, I get the method name (GetValue())
var expr = (InvocationExpressionSyntax)context.Node;
var memberAccess = expr.Expression as MemberAccessExpressionSyntax;
if (memberAccess?.Name.ToString() != "GetValue")
return;
3 - I then check to see if it's the right 'GetValue'
var memberSymbol = context.SemanticModel.GetSymbolInfo(memberAccess).Symbol as IMethodSymbol;
if (!memberSymbol?.OverriddenMethod.ToString().StartsWith("MyNamespace.MyThing.GetValue") ?? true)
return;
4 - Up to here, everything is fine. So I get the name of the variable
var e = memberAccess.Expression as IdentifierNameSyntax;
string variableName = e.Identifier.Text;
5 - now I'm stuck - my theory was to; get the containing method, find the single variable declaration that matches variableName, find usages of that, and ensure that HasValue is called before GetValue.
In short, using a Roslyn analyser (deriving from DiagnosticAnalyzer), how do I ensure that HasValue is called before GetValue?

Instead of registering for each Invocation, you might be better off registering for the entire method declaration. Then you can keep track of all MemberAccessExpressionSyntax and ensure that for a given variable that HasValue is called before GetValue. To do that, I would get the MemberAccessExpressionSyntax descendants from the MethodDeclaration node.
context.RegisterSyntaxNodeAction((analysisContext) =>
{
var invocations =
analysisContext.Node.DescendantNodes().OfType<MemberAccessExpressionSyntax>();
var hasValueCalls = new HashSet<string>();
foreach (var invocation in invocations)
{
var e = invocation.Expression as IdentifierNameSyntax;
if (e == null)
continue;
string variableName = e.Identifier.Text;
if (invocation.Name.ToString() == "HasValue")
{
hasValueCalls.Add(variableName);
}
if (invocation.Name.ToString() == "GetValue")
{
if (!hasValueCalls.Contains(variableName))
{
analysisContext.ReportDiagnostic(Diagnostic.Create(Rule, e.GetLocation()));
}
}
}
}, SyntaxKind.MethodDeclaration);

Related

How to create FUNC Action List with Parameters and Return Values

I am trying to create my first list of actions that I will be able to check a status within the passed object.
But I can't get it to work - its giving me an error on the return type. But if I change the return type to what it wants - then I can't pass values down.
Sample code:
public class Class1
{
public Main()
{
var decisionObject = new DecisionObject();
var decisionList = new List<Func<DecisionObject, DecisionObject>>
{
Method1(decisionObject),
Method2(decisionObject),
Method3(decisionObject)
};
var exitLoop = false;
foreach (var method in decisionList)
{
decisionObject = method(decisionObject);
switch (decisionObject.Status)
{
case Status1:
exitLoop = true;
break;
case Status2:
case Status3:
case Status4:
break;
}
if (exitLoop) break;
}
}
public Func<DecisionObject, DecisionObject> Method1(DecisionObject
decisionObject)
{
decisionObject = SomeOtherMethod(decisionObject);
return decisionObject;
}
}
What am I missing here?
If I'm not mistaken, Method1,Method2, and Method3 are simply supposed to accept a decision object and return a different one. So they would be defined like this (hopefully this is straightforward to you):
DecisionObject Method1(DecisionObject input)
{
var output = SomeMethod(input);
return output;
}
You then want to put all these methods into a list and execute them. To put them into a list, put the method names in the code without parentheses. That tells C# that you want a reference to the method itself, rather than the result of invoking the method.
var decisionList = new List<Func<DecisionObject, DecisionObject>>
{
Method1, //Do not invoke-- just store a reference to the method
Method2,
Method3
};
You can then invoke them by passing the decision object in:
foreach (var func in decisionList)
{
var result = func(decisionObject);
}
The key thing here to remember is that when you put parentheses after a symbol, it tells C# to invoke it. So don't put parentheses if all you want is a reference to the method itself.
decisionObject = SomeOtherMethod(decisionObject)
Isn't probably returning a func but a value.
You could do this:
public Func<DecisionObject, DecisionObject> Method1()
{
var myFunc = (myObject) => SomeOtherMethod(myObject);
return myFunc;
}
That will create and returns a new func that expects one parameter and invokes SomeOtherMethod.
Please note that the parameter of Method1 isn't needed in this approach and so I removed it.

How to find if a parameter to an invoked method is a variable (via "var/string") or an in-line string using Roslyn

I'm currently trying to find invocations of .ExecuteSqlCommand and examine the first value being passed to the sql param.
Here is an example of the differences I've found in our code base.
ExecuteSqlCommand("[sql statement here]");
vs.
var sql = "sql statement";
ExecuteSqlCommand(sql);
So far, I have this:
var invocations = root.DescendantNodes()
.OfType<InvocationExpressionSyntax>()
.Select(ie => ModelExtensions.GetSymbolInfo(model, ie).Symbol)
.Where(symbol => symbol != null && symbol.Name == "ExecuteSqlCommand");
foreach (var invocation in invocations)
{
var method = (IMethodSymbol)invocation;
foreach (var param in method.Parameters)
{
//I can't quite seem to get information from IParameterSymbol about whether the param is a string literal, or a reference to a string via a variable.
}
}
If the param is not a string, and instead, a var, then I'll need to get the value of the var (as much as it's defined at runtime).
I'm not too sure if this is a job for the SemanticModel or the SyntaxTree, but my GUESS is that the SemanticModel should have the richer information I need to let me discover what I'm looking for.
My overall goal is to interrogate the sql being passed to the ExecuteSqlCommand method.
Thanks!
SemanticModel.GetConstantValue is the API we have for handling this situation.
It can accept both a syntax node and an expression. You will still need to track the state of variables back to their declaration sites and determine if they were given a constant expression.
I would use SemanticModel.GetSymbolInfo.Symbol?.DeclaringSyntaxReferences.First() to find the declaration site of a variable and then check to see if its a constant expression.
The Syntax API could be used to extract the sql statement value but depends on whether the variable declaration (i.e. var sql = "sql statement";) is included as part of code submitted to the syntax tree.
For example, if it's part of the same method implementation as where ExcuteSqlCommand() is called then you can first get the name of variable (i.e. sql) passed to it and use that to find the matching variable declaration statement within that same method. Finally, the sql statement value (i.e. "sql statement") can be extracted from that.
The following code first checks if the sql value is passed as a string literal otherwise looks for the variable declaration. The assumption it's all within the same method:
// whatever c# *method* code contains the sql.
// otherwise the root of the tree would need to be changed to filter to a specific single `MethodDeclarationSyntax`.
string submittedCode = "public void SomeMethodContainingSql(){ ...//rest of code...";
var tree = CSharpSyntaxTree.ParseText(submittedCode);
var root = (CompilationUnitSyntax) tree.GetRoot();
var arguments = root
.DescendantNodes()
.OfType<InvocationExpressionSyntax>()
.First(node => node.DescendantNodes().OfType<IdentifierNameSyntax>()
.First()
.Identifier.Text == "ExecuteSqlCommand")
.ArgumentList.DescendantNodes().ToList();
string sqlStatementValue = "";
var literalExpression = arguments.OfType<LiteralExpressionSyntax>().FirstOrDefault();
if (literalExpression != null)
{
sqlStatementValue = literalExpression.GetText().ToString();
}
else
{
var variableName = arguments
.First()
.ToFullString();
var variableDeclaration = root
.DescendantNodes()
.OfType<VariableDeclarationSyntax>()
.Single(node => node.DescendantNodes().OfType<VariableDeclaratorSyntax>()
.First()
.Identifier.Text == variableName);
sqlStatementValue = variableDeclaration.DescendantNodes()
.OfType<LiteralExpressionSyntax>()
.First()
.DescendantTokens()
.First()
.Text;
}
Otherwise, may need to look for the variable declaration in other parts of the submitted code (ex. class fields, properties, other methods, etc.) which is a bit more cumbersome.
Unfortunately Roslyn cannot provide a variable's value in a common cases when values is defined at runtime, because Roslyn actually doesn't know all possible values which may pass from outside the program, it doesn't calculate them and so on so forth. But if you can limit the needed cases to a inlining strings or variables which was declared and initialized at strings, Roslyn may help you with this:
You need to keep InvocationExpressionSyntax (or directly their first arguments)
var invocations = root.DescendantNodes()
.OfType<InvocationExpressionSyntax>()
.Select(ie => (ModelExtensions.GetSymbolInfo(model, ie).Symbol, ie))
// Would be better to compare not method's name but it FQN
.Where((symbol, node)) => symbol != null && symbol.Name == "ExecuteSqlCommand" &&
symbol.Parameters.Length == 1 &&
symbol.Parameters[0].Type.SpecialType == SpecialType.System_String &&
node.ArgumentList.Arguments.Count == 1)
.Select((symbol, node) => node);
You need to check not method parameter, but method argument which was passed to it
foreach (var invocation in invocations)
{
var argument = invocation .ArgumentList.Arguments[0];
if (argument is LiteralExpressionSyntax literal && literal.IsKind(SyntaxKind.StringLiteralExpression))
{
// You find invocation of kind `ExecuteSqlCommand("sql")`
}
else
{
var argSymbol = ModelExtensions.GetSymbolInfo(model, argument).Symbol;
if (!(argSymbol is null) && (argSymbol.Kind == SymbolKind.Field || argSymbol.Kind == SymbolKind.Property || argSymbol.Kind == SymbolKind.Local))
{
if (argSymbol.DeclaringSyntaxReferences.Length == 1)
{
var declarationNode = argSymbol.DeclaringSyntaxReferences[0].GetSyntax();
// I'm actually don't remember what exactlly `GetSyntax` returns for fields or locals:
// VariableDeclaratorSyntax or one of it parent LocalDeclarationStatementSyntax and FieldDeclarationSyntax, but if it returns declarations you also can
// get from them VariableDeclaratorSyntax that you need, it's just be a more deep pattern matching
if (declarationNode is VariableDeclaratorSyntax declaratorSyntax &&
declaratorSyntax.EqualsValueClauseSyntax?.Value is LiteralExpressionSyntax literal2 && literal2.IsKind(SyntaxKind.StringLiteralExpression) )
{
// You find invocation of kind `ExecuteSqlCommand(variable)` where variable is local variable or field
}
else if (declarationNode is PropertyDeclarationSyntax property)
{
// You can do the same things for properties initializer or expression body that you was do for fields and locals to check your case,
// but it doesn't work for property with get/set accessors in a common cases
}
}
}
}
}

Expression Tree with string assignment and getting value

I have built my own SQL Query builder that breaks apart an Expression, however, I'm having an issue trying to get the value of string defined in the same function as the lambda expression.
Here is what I am trying to do in console app:
private static void MyBuilderTest()
{
var sqlBuilder = new SqlBuilder();
// Doesn't work -- NEED GUIDANCE HERE
var testValue = "Test"; // Defined in the same function as the lambda below
sqlBuilder.Select<FooObject>(o => o.FooValue == testValue);
// Works
var someObject = new SomeObject { SomeValue = "classTest };
sqlBuilder.Select<FooObject>(o => o.FooValue == someObject.SomeValue);
}
In my builder it subclasses from ExpressionVisitor, and I override the VisitMember. I found that a string defined in at the base Console level will come back as:
Node.Expression.NodeType == ExpressionType.Constant
The Node.Expression passes back properties of:
CanReduce = false
DebugView = ".Constant<ConsoleApplication1.Program+<>c__DisplayClass1>(ConsoleApplication1.Program+<>c__DisplayClass1)"
NodeType = Constant
Type = System.Type {System.RunetimeType}
Value = {ConsoleApplication1.Program}
The Node.Expression.Value contains:
testValue = "Test" (Type: string)
How do I get this value? I've tried several things, like:
var memberType = node.Expression.Type.DeclaringType;
This passes back a ConsoleApplication1.Program type.
However, when I do:
memberType.GetProperty("testValue"); // Declaring Type from Expression
It passes back null.
The above methods work fine if I place the lambda "strings" in a class, but doesn't work if they string is defined in the console function.
Can anyone tell me how to get the string value if it's defined at the function level of the lambda?
EDITED: Added VisitMember
protected override Expression VisitMember(MemberExpression node)
{
if (node.NodeType == ExpressionType.Constant)
{
// Node.Expression is a ConstantExpression type.
// node.Expression contains properties above
// And Has Value of: {ConsoleApplication1.Program}
// Expanding Value in Watch window shows: testValue = "Test"
// How do I get this value, if the ConsoleApplication1.Program type doesn't
// even know about it? Looks like maybe a dynamic property?
}
}
EDITED
Added code to the console app example to show what works and what doesn't.
The lambda in your example has "closed over" the testValue variable, meaning the compiler has captured it as a field of the same name in an automatically generated class called ConsoleApplication1.Program+<>c__DisplayClass1>. You can use normal reflection to get the current value of that field by casting the right hand-side of the binary expression into a MemberExpression.
var testValue = "hello";
var expr = (Expression<Func<string, bool>>) (x => x == testValue);
var rhs = (MemberExpression) ((BinaryExpression) expr.Body).Right;
var obj = ((ConstantExpression) rhs.Expression).Value;
var field = (FieldInfo) rhs.Member;
var value = field.GetValue(obj);
Debug.Assert(Equals(value, "hello"));
testValue = "changed";
value = field.GetValue(obj);
Debug.Assert(Equals(value, "changed"));
Alternatively you can change your variable into a constant.
const string testValue = "hello";
var expr = (Expression<Func<string, bool>>) (x => x == testValue);
var value = ((ConstantExpression) ((BinaryExpression) expr.Body).Right).Value;
Debug.Assert(Equals(value, "hello"));
Instead of doing this by yourself, have a look at PartialEvaluator from Matt Warren. It replaces all references to constants with the constants themselves.

Invoke Method of instance class through string

this link: http://www.codeproject.com/Articles/19911/Dynamically-Invoke-A-Method-Given-Strings-with-Met
explains clearly how to invoke a method when you have a method name + type as string variable.
I'm making a c# project with WatiN. All the WatiN methods I use are of the same form:
Examples: *(ById,.ByClass..; so should be connected, but then I could not set it bold :s )
browser.**TextField**(Find.By **Id**("name")).**TypeText**("my name");
browser.**Span**(Find.By **Class**("main_title")).**Click(**);
browser.**Link**(Find.By **Id**("mid_link")).**Click(**);
As you can see, this always consist of 3 methods which are variable. I created a class webElement consisted of the string properties: tag, type, search, action.
Where in example -> tag = "TextField"; type = "Id", search = "name"; action = "TypeText".
To get the web-elements dynamically, I created a WebHandler class where I try to dynamically call the right methods.
So a main class has a list of all the webElement objects and can give the right one at a given time to the WebHandler class. The Webhandler class should now invoke each element dynamically. I use the same invoke method as in given url, so my code to call it is:
class WebHandler:
private IE browser = new IE("google.com");
public void method(WebElement webElement)
{
//Get the findBy dynamically | this works
WatiN.Core.Constraints.Constraint findBy =
(WatiN.Core.Constraints.Constraint)InvokeMethod("WatiN.Core.Find, WatiN.Core", "By" + webElement.Type, webElement.Search); //where type = "Id" and search = "name"
//Get the tag (like textfield, link, span) dynamically | this does not work
Type aType = Type.GetType("WatiN.Core." + webElement.Tag, "WatiN.Core") //how can I set the element variable to this type? aType element -> Does not work
aType element = (WatiN.Core.TextField)InvokeMethod("this.browser", webElement.Tag, findBy); //tag = TextField
element.TypeText("a name"); //same problem as above | so should be invoked
}
QUESTIONS:
How do I invoke method (TextField) of instance class IE
(browser) dynamically using his string version "TextField" as variable? Another way of phrasing it would be: How do I get current variable (browser) by using it's string version "browser"?
How do I set type of variable element dynamically? So when webElement.Tag = Textfield then type should be WatiN.Core.TexField
element = .. (see code)
OWN CONSIDERATIONS:
Main problem I found is that you can only invoke a method from a type, so not from an instance of that type. Is there a way to do this anyway?
This line
Type aType = Type.GetType("WatiN.Core" + webElement.Tag)
does not have a dot after Core. It seems as if Core is a namespace and should thus be separated from the Tag name.
The gist of this is you get the Type you want, then use reflection to get the methods, then invoke the given method, passing the instance in.
So, something like this:
Type aType = Type.GetType(string.Format("WatiN.Core.{0}.WatiN.Core", webElement.Tag));
MethodInfo method = aType.GetMethod("TextField");
method.Invoke(this.browser, webElement.Tag, findBy);
The key bits here are:
Get the Type
Get the Method
Invoke the method with the instance you want
There are shortcuts, and I probably don't have the specifics right for your question, but that should get you close to what you want.
Here ya go, threw this together in LINQPad, but should be more-or-less portable:
void Main()
{
WatiN.Core.Browser theBrowser = new WatiN.Core.IE("google.com");
Foo(theBrowser, "Id", "gbqfq", "TextField", "TypeText", "Search for this");
}
public void Foo(WatiN.Core.Browser browser, string findTypeBy, string search, string tagName, string elementMethodName, params object[] argsForMethod)
{
var watinCoreAsm = Assembly.LoadWithPartialName("WatiN.Core");
if(watinCoreAsm == null) return;
var watinCoreTypes = watinCoreAsm.GetTypes();
if(watinCoreTypes == null) return;
var findType = watinCoreTypes.FirstOrDefault(type => type.Name == "Find");
if(findType == null) return;
var constraintInstance = findType.GetMethod("By" + findTypeBy, new Type[]{ typeof(string) }).Invoke(null, new[]{search});
if(constraintInstance == null) return;
var browserAccessor = browser.GetType().GetMethod(tagName, new Type[]{ constraintInstance.GetType() });
if(browserAccessor == null) return;
var resultElement = browserAccessor.Invoke(browser, new[]{ constraintInstance });
if(resultElement == null) return;
var elementMethod = resultElement.GetType().GetMethod(elementMethodName);
if(elementMethod == null) return;
elementMethod.Invoke(resultElement, argsForMethod);
}

Test if a property is available on a dynamic variable

My situation is very simple. Somewhere in my code I have this:
dynamic myVariable = GetDataThatLooksVerySimilarButNotTheSame();
//How to do this?
if (myVariable.MyProperty.Exists)
//Do stuff
So, basically my question is how to check (without throwing an exception) that a certain property is available on my dynamic variable. I could do GetType() but I'd rather avoid that since I don't really need to know the type of the object. All that I really want to know is whether a property (or method, if that makes life easier) is available. Any pointers?
I think there is no way to find out whether a dynamic variable has a certain member without trying to access it, unless you re-implemented the way dynamic binding is handled in the C# compiler. Which would probably include a lot of guessing, because it is implementation-defined, according to the C# specification.
So you should actually try to access the member and catch an exception, if it fails:
dynamic myVariable = GetDataThatLooksVerySimilarButNotTheSame();
try
{
var x = myVariable.MyProperty;
// do stuff with x
}
catch (RuntimeBinderException)
{
// MyProperty doesn't exist
}
I thought I'd do a comparison of Martijn's answer and svick's answer...
The following program returns the following results:
Testing with exception: 2430985 ticks
Testing with reflection: 155570 ticks
void Main()
{
var random = new Random(Environment.TickCount);
dynamic test = new Test();
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 100000; i++)
{
TestWithException(test, FlipCoin(random));
}
sw.Stop();
Console.WriteLine("Testing with exception: " + sw.ElapsedTicks.ToString() + " ticks");
sw.Restart();
for (int i = 0; i < 100000; i++)
{
TestWithReflection(test, FlipCoin(random));
}
sw.Stop();
Console.WriteLine("Testing with reflection: " + sw.ElapsedTicks.ToString() + " ticks");
}
class Test
{
public bool Exists { get { return true; } }
}
bool FlipCoin(Random random)
{
return random.Next(2) == 0;
}
bool TestWithException(dynamic d, bool useExisting)
{
try
{
bool result = useExisting ? d.Exists : d.DoesntExist;
return true;
}
catch (Exception)
{
return false;
}
}
bool TestWithReflection(dynamic d, bool useExisting)
{
Type type = d.GetType();
return type.GetProperties().Any(p => p.Name.Equals(useExisting ? "Exists" : "DoesntExist"));
}
As a result I'd suggest using reflection. See below.
Responding to bland's comment:
Ratios are reflection:exception ticks for 100000 iterations:
Fails 1/1: - 1:43 ticks
Fails 1/2: - 1:22 ticks
Fails 1/3: - 1:14 ticks
Fails 1/5: - 1:9 ticks
Fails 1/7: - 1:7 ticks
Fails 1/13: - 1:4 ticks
Fails 1/17: - 1:3 ticks
Fails 1/23: - 1:2 ticks
...
Fails 1/43: - 1:2 ticks
Fails 1/47: - 1:1 ticks
...fair enough - if you expect it to fail with a probability with less than ~1/47, then go for exception.
The above assumes that you're running GetProperties() each time. You may be able to speed up the process by caching the result of GetProperties() for each type in a dictionary or similar. This may help if you're checking against the same set of types over and again.
Maybe use reflection?
dynamic myVar = GetDataThatLooksVerySimilarButNotTheSame();
Type typeOfDynamic = myVar.GetType();
bool exist = typeOfDynamic.GetProperties().Where(p => p.Name.Equals("PropertyName")).Any();
Just in case it helps someone:
If the method GetDataThatLooksVerySimilarButNotTheSame() returns an ExpandoObject you can also cast to a IDictionary before checking.
dynamic test = new System.Dynamic.ExpandoObject();
test.foo = "bar";
if (((IDictionary<string, object>)test).ContainsKey("foo"))
{
Console.WriteLine(test.foo);
}
The two common solutions to this include making the call and catching the RuntimeBinderException, using reflection to check for the call, or serialising to a text format and parsing from there. The problem with exceptions is that they are very slow, because when one is constructed, the current call stack is serialised. Serialising to JSON or something analogous incurs a similar penalty. This leaves us with reflection but it only works if the underlying object is actually a POCO with real members on it. If it's a dynamic wrapper around a dictionary, a COM object, or an external web service, then reflection won't help.
Another solution is to use IDynamicMetaObjectProvider to get the member names as the DLR sees them. In the example below, I use a static class (Dynamic) to test for the Age field and display it.
class Program
{
static void Main()
{
dynamic x = new ExpandoObject();
x.Name = "Damian Powell";
x.Age = "21 (probably)";
if (Dynamic.HasMember(x, "Age"))
{
Console.WriteLine("Age={0}", x.Age);
}
}
}
public static class Dynamic
{
public static bool HasMember(object dynObj, string memberName)
{
return GetMemberNames(dynObj).Contains(memberName);
}
public static IEnumerable<string> GetMemberNames(object dynObj)
{
var metaObjProvider = dynObj as IDynamicMetaObjectProvider;
if (null == metaObjProvider) throw new InvalidOperationException(
"The supplied object must be a dynamic object " +
"(i.e. it must implement IDynamicMetaObjectProvider)"
);
var metaObj = metaObjProvider.GetMetaObject(
Expression.Constant(metaObjProvider)
);
var memberNames = metaObj.GetDynamicMemberNames();
return memberNames;
}
}
Denis's answer made me think to another solution using JsonObjects,
a header property checker:
Predicate<object> hasHeader = jsonObject =>
((JObject)jsonObject).OfType<JProperty>()
.Any(prop => prop.Name == "header");
or maybe better:
Predicate<object> hasHeader = jsonObject =>
((JObject)jsonObject).Property("header") != null;
for example:
dynamic json = JsonConvert.DeserializeObject(data);
string header = hasHeader(json) ? json.header : null;
Well, I faced a similar problem but on unit tests.
Using SharpTestsEx you can check if a property existis. I use this testing my controllers, because since the JSON object is dynamic, someone can change the name and forget to change it in the javascript or something, so testing for all properties when writing the controller should increase my safety.
Example:
dynamic testedObject = new ExpandoObject();
testedObject.MyName = "I am a testing object";
Now, using SharTestsEx:
Executing.This(delegate {var unused = testedObject.MyName; }).Should().NotThrow();
Executing.This(delegate {var unused = testedObject.NotExistingProperty; }).Should().Throw();
Using this, i test all existing properties using "Should().NotThrow()".
It's probably out of topic, but can be usefull for someone.
Following on from the answer by #karask, you could wrap the function as a helper like so:
public static bool HasProperty(ExpandoObject expandoObj,
string name)
{
return ((IDictionary<string, object>)expandoObj).ContainsKey(name);
}
For me this works:
if (IsProperty(() => DynamicObject.MyProperty))
; // do stuff
delegate string GetValueDelegate();
private bool IsProperty(GetValueDelegate getValueMethod)
{
try
{
//we're not interesting in the return value.
//What we need to know is whether an exception occurred or not
var v = getValueMethod();
return v != null;
}
catch (RuntimeBinderException)
{
return false;
}
catch
{
return true;
}
}
If you control the type being used as dynamic, couldn't you return a tuple instead of a value for every property access? Something like...
public class DynamicValue<T>
{
internal DynamicValue(T value, bool exists)
{
Value = value;
Exists = exists;
}
T Value { get; private set; }
bool Exists { get; private set; }
}
Possibly a naive implementation, but if you construct one of these internally each time and return that instead of the actual value, you can check Exists on every property access and then hit Value if it does with value being default(T) (and irrelevant) if it doesn't.
That said, I might be missing some knowledge on how dynamic works and this might not be a workable suggestion.
If your use case is to convert an api response, carrying about only a few fields, you can use this:
var template = new { address = new { street = "" } };
var response = JsonConvert.DeserializeAnonymousType(await result.Content.ReadAsStringAsync(), template);
string street = response?.address?.street;
Here is the other way:
using Newtonsoft.Json.Linq;
internal class DymanicTest
{
public static string Json = #"{
""AED"": 3.672825,
""AFN"": 56.982875,
""ALL"": 110.252599,
""AMD"": 408.222002,
""ANG"": 1.78704,
""AOA"": 98.192249,
""ARS"": 8.44469
}";
public static void Run()
{
dynamic dynamicObject = JObject.Parse(Json);
foreach (JProperty variable in dynamicObject)
{
if (variable.Name == "AMD")
{
var value = variable.Value;
}
}
}
}
In my case, I needed to check for the existence of a method with a specific name, so I used an interface for that
var plugin = this.pluginFinder.GetPluginIfInstalled<IPlugin>(pluginName) as dynamic;
if (plugin != null && plugin is ICustomPluginAction)
{
plugin.CustomPluginAction(action);
}
Also, interfaces can contain more than just methods:
Interfaces can contain methods, properties, events, indexers, or any
combination of those four member types.
From: Interfaces (C# Programming Guide)
Elegant and no need to trap exceptions or play with reflexion...
I know this is really old post but here is a simple solution to work with dynamic type in c#.
can use simple reflection to enumerate direct properties
or can use the object extention method
or use GetAsOrDefault<int> method to get a new strongly typed object with value if exists or default if not exists.
public static class DynamicHelper
{
private static void Test( )
{
dynamic myobj = new
{
myInt = 1,
myArray = new[ ]
{
1, 2.3
},
myDict = new
{
myInt = 1
}
};
var myIntOrZero = myobj.GetAsOrDefault< int >( ( Func< int > )( ( ) => myobj.noExist ) );
int? myNullableInt = GetAs< int >( myobj, ( Func< int > )( ( ) => myobj.myInt ) );
if( default( int ) != myIntOrZero )
Console.WriteLine( $"myInt: '{myIntOrZero}'" );
if( default( int? ) != myNullableInt )
Console.WriteLine( $"myInt: '{myNullableInt}'" );
if( DoesPropertyExist( myobj, "myInt" ) )
Console.WriteLine( $"myInt exists and it is: '{( int )myobj.myInt}'" );
}
public static bool DoesPropertyExist( dynamic dyn, string property )
{
var t = ( Type )dyn.GetType( );
var props = t.GetProperties( );
return props.Any( p => p.Name.Equals( property ) );
}
public static object GetAs< T >( dynamic obj, Func< T > lookup )
{
try
{
var val = lookup( );
return ( T )val;
}
catch( RuntimeBinderException ) { }
return null;
}
public static T GetAsOrDefault< T >( this object obj, Func< T > test )
{
try
{
var val = test( );
return ( T )val;
}
catch( RuntimeBinderException ) { }
return default( T );
}
}
As ExpandoObject inherits the IDictionary<string, object> you can use the following check
dynamic myVariable = GetDataThatLooksVerySimilarButNotTheSame();
if (((IDictionary<string, object>)myVariable).ContainsKey("MyProperty"))
//Do stuff
You can make a utility method to perform this check, that will make the code much cleaner and re-usable

Categories