c# dynamic and extension method solution? - c#

I have a method in Base class which calls ( by reflection to another method).
type.InvokeMember(context.Request["MethodName"],
System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance,
null,
this,
new object[] { context, Jobj }); // jObj is dynamic
jObj parameter type is dynamic ( can't change this type).
if the MethodName string value is : "getFinanceDetails" so that method is called..
void getFinanceDetails(object contextObj, dynamic obj)
{
//Here I need to do obj["Inv_num"].ToString().Decrpyt() ( my extension method).
//but it goes Bang cause I cant use extension method for dynamic.
//But I cant also send it decrypted from base cause not all values are encrpyrted.
}
However - I did solve it by using (inside the method):
((object) obj["Inv_num"]).ToString().Decrypt();
But I dont want to cast every time to object , just to enable extension method.
Is there anything I can do with the param type sending to fix it ?
my desire :
I want to be able to do : obj.ToString().Decrpyt() obj["Inv_num"].ToString().Decrpyt()
edit
public static string Decrypt(this string obj)
{
Func<string, string> Decrypt = Encryptions.GetDecryptedCode;
return Decrypt(obj);
}
obj ( in this case is IDictionary<string , object>) .
so I should be able to read properties. (inv_num in this sample.

Probably not exactly the syntax you were looking for but you could call the extension method as a simple static method on the dynamic object:
void getFinanceDetails(object contextObj, dynamic obj)
{
var decryptedValue = MyExtensions.Decrypt(obj);
}
This obviously assumes that at runtime obj is of the correct type that your extension method operates on. In your question you have shown some obj["Inv_num"] as if obj was a complex type with a property called Inv_num which is of type string. So you might need to adjust the call on the proper type:
var decryptedValue = MyExtensions.Decrypt(obj["Inv_num"]);

Assuming obj["Inv_num"].ToString() already returns the right value, you could easily do it in two steps:
string text = obj["Inv_num"].ToString();
var decrypted = text.Decrypt();
To be honest, it's not clear why getFinanceDetails (which should be changed to follow .NET naming conventions) can't be written as:
void getFinanceDetails(object contextObj, IDictionary<string, object> obj)
{
var decrypted = obj["Inv_num"].ToString().Decrypt();
}
Do you ever need to call it with something that doesn't implement IDictionary<string, object>?

Related

How to execute static methods by name

I have an XML file with classes name like this:
<ActiveMonitorsList>
<MonitorName>CertificatesMonitor</MonitorName>
<MonitorName>ServicesMonitor</MonitorName>
<MonitorName>LogsMonitor</MonitorName>
<MonitorName>DBMonitor</MonitorName>
</ActiveMonitorsList>
Each of this classes containts a method: bool SingleCheck();
I would like to execute this bool SingleCheck() method for each class that is in this XML file.
What is the best way to do this?
This is what I have so far - it doesn't work:
foreach (string monitorName in monitorsList)
{
Type thisType = GetType();
MethodInfo singleMonitorMethod = thisType.GetMethod("{monitorName}.SingleCheck");
bool methodResult = singleMonitorMethod.Invoke(...);
}
In place of (...) - don't know what to put here, but I want to get
the result of the method (it's always bool).
All of those methods I want to pass as paramters are static.
I guess delegates, Actions or Func<> have to go in here...
Thank You very much in advance!
Edit: Each name in XML points to a separate class. Each class have the same named method: public static bool SingleCheck().
What I want to do is:
get all the monitors names (classes names will be the same)
invoke a method (it has the same name in each class) inside EVERY
class present on that list.
EDIT - PROBLEM SOLVED:
When I first created my project, I included separate folder for all monitors. Then I changed my mind, deleted this folder and added manually SAME FILES to my solution. In this way - those files still had "using <namespace>.Monitors"...
And that's why I couldn't list those classes and the Types were still nulls...
Thanks for all suggestions ! ;)
I would suggest to take this overload of the method Invoke It wants an object(calling instance) and a set of input parameters for the method from you.
Since it is a static method, you can calmly pass null as the first parameter and because you method does not have any parameters you again can calmly pass null as the second value. Don't forget to cast object to the corresponding return type. In your case bool.
bool methodResult = (bool)singleMonitorMethod.Invoke(null, null);
To get the correct Type you actually need to know the namespace! So this would look like this:
foreach (string monitorName in monitorsList)
{
string typeName = $"{yourNameSpace}.{monitorName}";
Type thisType = Type.GetType(typeName);
MethodInfo singleMonitorMethod = thisType.GetMethod("SingleCheck");
bool methodResult = (bool)singleMonitorMethod.Invoke(null, null);
}
If the loop is in the same namespace this should also work:
Type thisType = Type.GetType($"{GetType().Namespace}.{monitorName}");
thisType.GetMethod("{monitorName}.SingleCheck") won't work because of two reasons. 1) You forgot the string interpolation $-sign and thus are searching for a method called "{monitorName}.SingleCheck" which obviously can't exist with such a name. 2) Instead of thisType you need to provide the type containing the method.
Invoke needs to be called with the instance as first parameter - null for static methods - and an object array for the method parameters.
Assuming that your monitor classes are in the same assembly like your current type you would need to do the following:
foreach (string monitorName in monitorsList)
{
Type monitorType = GetType().Assembly.GetExportedTypes().Single(x => x.Name == monitorName);
MethodInfo singleMonitorMethod = monitorType.GetMethod("SingleCheck");
bool methodResult = (bool)singleMonitorMethod.Invoke(null, Array.Empty<object>());
}
I prefer Array.Empty over new object[0] or new object[] { } because it doesn't create a new object every time.
Edited: Changed the type discovery according to Mong Zhu's comment that GetType(monitorName) does need the fully-qualified name.

generate predictable unique string based on a generic objects content

Story
I'm trying to write a generic method which combines property names, types and content value to generate a unique string for the value held by the object passed.
The idea is to generate a unique SHA3-512 Hash based on the generated string sequence which can be used to compare objects on generic bases by looking at their content.
Example
Let's say we have a class like this ...
class MyClass {
private Int32 Id = 5;
public String Name = "some string";
protected DateTime CreateDate = DateTime.Parse("2017-08-21 15:00:07");
}
... and the mentioned method to generate the unique string
static String GetContentString<T>(T obj) where T : class {
...
}
In theory this should work somewhat like this:
var myObj = new MyClass();
var uniqueContentString = GetContentString(myObj);
Console.WriteLine(uniqueContentString);
>>> Id:Int32:5$Name:String:some string$CreateDate:DateTime:2017-08-21 15:00:07
Problem
I'm having difficulties building the GetContentString Method. This is what I have already:
Object obj = ... // given object
Type type = obj.GetType();
IList<PropertyInfo> propertyInfos = type.GetProperties().Where(x => x.CanRead).ToList(); // Marker #2
StringBuilder sb = new StringBuilder();
foreach (PropertyInfo pi in propertyInfos)
{
sb.Append(pi.Name);
sb.Append(":");
sb.Append(pi.PropertyType.Name);
sb.Append(":");
sb.Append(pi.GetValue(obj) ?? "[ISNULL]"); // Marker #1
sb.Append(":");
}
return sb.ToString();
I tried running the method for a few different types of values like "some string" or 1234 (Int32) and ran into a few issues.
Given a string, the method call throws an exception of type System.Reflection.TargetParameterCountException and the message Parameter count mismatch at #1. I found out that an optional index can be passed to an overloaded version of pi.GetValue(..) which then returns one of the single letters. But how do you know when to stop? If you call an index which doesn't exist it throwns an exception of the type System.Reflection.TargetInvocationException. How do you get the value of a string object using reflection?
Given an integer value, the method call doesn't find any properties at #2. Which brings up the question of how to get the value of an integer object using reflection?
And also some general questions; do you guys think this is a good approach to get a unique string? Is reflection the way to go here? Is it even possible to write a generic solution to this problem?
Without looking at reflection, how about JSON serialization with something that .net framework is able to ?
Reflection isn't something extremely fast and you'll run into issues at the first unhandled exception.
Then, you should do that recursivly if your objects can contains complex properties, wich is not a problem with json serialization !

Referring to dynamic members of C# 'dynamic' object

I'm using JSON.NET to deserialize a JSON file to a dynamic object in C#.
Inside a method, I would like to pass in a string and refer to that specified attribute in the dynamic object.
For example:
public void Update(string Key, string Value)
{
File.Key = Value;
}
Where File is the dynamic object, and Key is the string that gets passed in. Say I'd like to pass in the key "foo" and a value of "bar", I would do:
Update("foo", "bar");, however due to the nature of the dynamic object type, this results in
{
"Key":"bar"
}
As opposed to:
{
"foo":"bar"
}
Is it possible to do what I'm asking here with the dynamic object?
I suspect you could use:
public void Update(string key, string Value)
{
File[key] = Value;
}
That depends on how the dynamic object implements indexing, but if this is a Json.NET JObject or similar, I'd expect that to work. It's important to understand that it's not guaranteed to work for general dynamic expressions though.
If you only ever actually need this sort of operation (at least within the class) you might consider using JObject as the field type, and then just exposing it as dynamic when you need to.
Okay so it turns out I'm special. Here's the answer for those that may stumble across this in future,
Turns out you can just use the key like an array index and it works perfectly. So:
File[Key] = Value; Works the way I need as opposed to
File.Key = Value;
Thanks anyway!
You can do it, if you're using JObject from JSON.NET. It does not work with an ExpandoObject.
Example:
void Main()
{
var j = new Newtonsoft.Json.Linq.JObject();
var key = "myKey";
var value = "Hello World!";
j[key] = value;
Console.WriteLine(j["myKey"]);
}
This simple example prints "Hello World!" as expected. Hence
var File = new Newtonsoft.Json.Linq.JObject();
public void Update(string key, string Value)
{
File[key] = Value;
}
does what you expect. If you would declare File in the example above as
dynamic File = new ExpandoObject();
you would get a runtime error:
CS0021 Cannot apply indexing with [] to an expression of type 'ExpandoObject'

Get value from anonymous type

I have a method as following:
public void MyMethod(object obj){
// implement
}
And I call it like this:
MyMethod(new { myparam= "waoww"});
So how can I implement MyMethod() to get myparam value?
Edit
I use this:
dynamic d= obj;
string param = d.myparam;
but the error rise :
'object' does not contain a definition for 'myparam'
also I use breakpoint and I see the d have myparam string property.
And is there any way to check dynamic type to if contain any property like this:
if(d.contain(myparam))?
Edit II
This is my main code:
public static MvcHtmlString SecureActionLink(this HtmlHelper htmlHelper,
string linkText, string actionName, string controllerName,
object routeValues, object htmlAttributes) {
string areaName =
(string)htmlHelper.ViewContext.RouteData.DataTokens["area"];
dynamic areaObject = routeValues;
if(areaObject != null && !string.IsNullOrEmpty(areaObject.area))
areaName = areaObject.area;
// more
}
and call it as:
<p>#Html.SecureActionLink("Secure Link between Areas", "Index", "Context",
new { area = "Settings" }, null)</p>
And Error is:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'object' does not contain a
definition for 'area'
Line 303: dynamic areaObject = routeValues;
Line 304:
Line 305: if(areaObject != null && !string.IsNullOrEmpty(areaObject.area))
Line 306: areaName = areaObject.area;
Line 307:
Source File: D:\Projects\MyProject\HtmlHelpers\LinkExtensions.cs Line: 305
Edit III
This is my AssemblyInfo of HtmlHelper definition:
[assembly: AssemblyTitle("MyProject.Presentation")]
[assembly: InternalsVisibleTo("cpanel.MyProject.dev")]
but there is an error yet: 'object' does not contain a definition for 'area'
I use different assemblies but how can it possible, when I use breakpoint I can see that my dynamic areaobject have area name property and also I can see the value of that, but the error say: 'object' does not contain a definition for 'area' I can't figure it how it can be possible?
Edit
I change the assembly and now dynamic type is internal but the error remains as before
Use this one:
string area = areaObject.GetType().GetProperty("area").GetValue(areaObject, null);
Well, you could use dynamic typing if you're using C# 4:
public void MyMethod(object obj) {
dynamic d = obj;
Console.WriteLine(d.myparam);
}
It does beg the question of why you're not using a named type though. Anonymous types aren't really designed to be shared among different methods like this.
EDIT: Note that if this is in a different assembly to the original code creating the object, you'll need to use [InternalsVisibleTo] as anonymous types are internal.
First off, as others have said: don't do this in the first place. That's not how anonymous types were intended to be used.
Second, if you are bent upon doing it, there are a number of ways to do so. The slow and dangerous way is to use dynamic, as others have said.
The fast and dangerous way is to use "cast by example:
static T CastByExample<T>(object obj, T example)
{
return (T)obj;
}
static void M(object obj)
{
var anon = CastByExample(obj, new { X = 0 });
Console.WriteLine(anon.X); // 123
}
static void N()
{
M(new { X = 123 });
}
is there any way to check dynamic type to if contain any property?
Use Reflection. Of course, if you are going to use Reflection then there is no need to use dynamic in the first place. You use dynamic to avoid using Reflection, so if you are going to be using Reflection anyways, you might as well just keep on using it.
It sounds like you are trying to do something that is hard to do in C#. I would reevaluate whether you want to be doing that, and if you do, whether C# is the language for you. A dynamic language like IronPython might be a better fit for your task.
Everybody says "don't do it in the first place", but this is exactly what asp.mvc does!
(Don't get me wrong I don't like it myself, but if you are writing custom html helpers you want to call them the way you call the normal html helpers...)
And you can use asp.mvc to make your life easier:
public void MyMethod(object obj){
var dic=new System.Web.Routing.RouteValueDictionary(obj);
string param=dic["myparam"] as string;
}
Another way is convert anonymous data to json and then convert to c# json object. You can read all data with this way easily.

Get delegate arguments inside delegate

Could someone please help me to understand how to get all parameters passed to delegate inside delegate itself?
I have class :
public class ShopManager : ShopEntities
{
public ShopManager getWhere(Func<Object, Object> dataList)
{
var x = dataList.???; // how to get arguments?
return this;
}
public Object getLike(Object dataValue)
{
return dataValue;
}
}
Then i call it as :
ShopManager shopManager = new ShopManager()
var demo = shopManager.getWhere(xxx => shopManager.getLike("DATA"));
The question is : how to get passed parameters "xxx" and "DATA" inside method getWhere()?
Thanks in advance.
You can't because it's the other way around. You can't get the arguments because the delegate does not hold them; the getWhere method will need to pass a value for the xxx parameter when invoking the delegate. The anonymous method that the delegate refers to will then receive this value as the xxx parameter, and in turn pass the string "DATA" as argument for the dataValue parameter when calling getLike. The argument values as such are not part of the delegate's state.
If you want to get information about the parameters as such (not their values), you can do that:
// get an array of ParameterInfo objects
var parameters = dataList.Method.GetParameters();
Console.WriteLine(parameters[0].Name); // prints "xxx"
If you use:
public ShopManager getWhere(Expression<Func<Object, Object>> dataList)
then you can divide the Expression into its subexpressions and parse them. But I'm not sure if using a delegate like you do is even the right thing.
You can't do it (easily). But I don't understand your idea. For what reason do you need to look into a dataList? This is just an anonymous method, you can call it and get results, you shouldn't need to examine or modify it at all.
What is your idea? Why not just call shopManager.getLike() ?
you can get the name of function by doing something like below.
var x = dataList.GetInvocationList().FirstOrDefault().Method.GetParameters();
sring name = x.FirstOrDefault().Name
this will print name as 'xxx'
Arguments are what you will provide while invoking the delegate via dataList(args), and not by the recipient of the invocation. If you want to provide additional information to getWhere() , you can try the following ....
public ShopManager getWhere(Func<Object, Object> dataList, params object[] additonalData)
{
// inspect the additionalData
}
Thanks for replies guys, i decided to use Expression> instead of common delegate. This allows to get both sides of expression - LHS and RHS.
For those who are interested in answer, this is it :
http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/0f6ca823-dbe6-4eb6-9dd4-6ee895fd07b5?prof=required
Thanks for patience and attention.
public static List<object> GetMethodParameterValues(Delegate method)
{
var target = method.Target;
if (target == null) return null;
var fields = target.GetType().GetFields();
var valueList = fields.Select(field => field.GetValue(target)).ToList();
return valueList;
}

Categories