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.
Related
I am trying to get the MethodInfo from a method TableExists<T> so I can call it with a type.
The method is declared inside OrmLiteSchemaApi class. There are 2 overloads:
public static bool TableExists<T>(this IDbConnection dbConn)
{
// code omitted
}
public static bool TableExists(this IDbConnection dbConn, string tableName, string schema = null)
{
// code omitted
}
I am trying to get the MethodInfo like this:
var tableMethod = typeof(OrmLiteSchemaApi).GetMethod("TableExists");
But it generates exception:
System.Reflection.AmbiguousMatchException: 'Ambiguous match found.'
I could only find an old question related to this that suggested to pass an empty object array as parameter but this doesn't seem to work for .net core.
I guess I need to specify the specific overload but I am not sure exactly how.
How do I get the MethodInfo?
You can use GetMethods (plural!) to get an array of all matching methods, and then look for the one which has IsGenericMethod:
var tm = typeof(OrmLiteSchemaApi)
.GetMethods()
.Where(x => x.Name == "TableExists")
.FirstOrDefault(x => x.IsGenericMethod);
I recommend this over using parameter specifiers, since it'll give you an object you can step through at debug time if there are ever any problems.
Passing an empty object array would only work if you're looking for a function with no parameters. Instead, you need to use a different overload of GetMethod that specifies the types of parameters as a type array. That way you can tell it which reference to get by specifying which types of parameters it should look for.
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.
string thing = "etc";
thing = thing.GetName();
//now thing == "thing"
Is this even possible?
public static string GetName(this object obj)
{
return ... POOF! //should == "thing"
}
I agree #Reed's answer. However, if you REALLY want to achieve this functionality, you could make this work:
string thing = "etc";
thing = new{thing}.GetName();
The GetName extension method would simply use reflection to grab the name of the first property from the anonymous object.
The only other way would be to use a Lambda Expression, but the code would definitely be much more complicated.
No. At the point you're using it, the "name" would be "obj" - This could be retrieved (with debugging symbols in place) via MethodBase.GetCurrentMethod().GetParameters()[0].Name.
However, you can't retrieve the variable name from the calling method.
If you need the original variable name inside an extension method, I think it's best to do this:
thing.DoSomething(nameof(thing));
public static string DoSomething(this object obj, string name) {
// name == "thing"
}
New in C# 6 is nameof() which would replace the extension method entirely.
if (x == null) throw new ArgumentNullException(nameof(x));
WriteLine(nameof(person.Address.ZipCode)); // prints "ZipCode”
Somewhat related is the CallerMemberAttribute which will get the name of the method where the function was called. A useful comparison of the two methods, with examples relating to PropertyChanged events, also talks about the IL code generated (TL;DR: they're the same).
I have a C# method say:
MyMethod(int num, string name, Color color, MyComplexType complex)
Using reflection, how can I distinctly identify each of the parameter types of any method?
I want to perform some task by parameter type. If the type is simple int, string or boolean then I do something, if it is Color, XMLDocument, etc I do something else and if it is user defined type like MyComplexType or MyCalci etc then I want to do certain task.
I am able to retrieve all the parameters of a method using ParameterInfo and can loop through each parameter and get their types. But how can I identify each data type?
foreach (var parameter in parameters)
{
//identify primitive types??
//identify value types
//identify reference types
}
Edit: this is apart of my code to create a propert grid sort of page where I want to show the parameter list with data types for the selected method. If the parameter has any userdefined type/reference type then I want to expand it further to show all the elements under it with datatypes.
Make use of ParameterInfo.ParameterType
using System;
using System.Reflection;
class parminfo
{
public static void mymethod (
int int1m, out string str2m, ref string str3m)
{
str2m = "in mymethod";
}
public static int Main(string[] args)
{
Console.WriteLine("\nReflection.Parameterinfo");
//Get the ParameterInfo parameter of a function.
//Get the type.
Type Mytype = Type.GetType("parminfo");
//Get and display the method.
MethodBase Mymethodbase = Mytype.GetMethod("mymethod");
Console.Write("\nMymethodbase = " + Mymethodbase);
//Get the ParameterInfo array.
ParameterInfo[]Myarray = Mymethodbase.GetParameters();
//Get and display the ParameterInfo of each parameter.
foreach (ParameterInfo Myparam in Myarray)
{
Console.Write ("\nFor parameter # " + Myparam.Position
+ ", the ParameterType is - " + Myparam.ParameterType);
}
return 0;
}
}
If you need to check the System.Type once retrieved you can use IsPrimitive and IsByRef as mentioned by David. In addition you can also use IsValueType. There are a significant number of Is* properties within the System.Type class. Your best bet would be to check the MSDN documentation on each Is* property ie...IsClass states...
Gets a value indicating whether the
Type is a class; that is, not a value
type or interface.
Therefore one could deduce that IsValueType does not need to be called. Keep in mind that a given type can return true across multiple properties in that IsClass could return true AND IsPassByRef could return true. Perhaps provide logic for the known CLR types since those will not change and you know those ahead of time and then build in the logic for complex types as defined by the user. You could take the approach of building in the logic to do this for the CLR types as well; either way would work.
To get the actual Type of the parameter use the ParameterType on the ParameterInfo value. With that value there are several ways you can use it to identify the type. The easiest is with a direct comparison to a known type
if (parameter.ParameterType == typeof(int)) {
...
}
Or in cases where the type is not available a name match can be used (although this is a bit flakier as refactor operations may miss the string constant and silently break the application)
if (parameter.ParameterType.Name == "TheTypeName") {
...
}
How could I go about calling a method on a static class given the class name and the method name, please?
For example:
Given System.Environment and GetFolderPath, I'd like to use Reflection to call Environment.GetFolderPath().
Just
Type.GetType(typeName).GetMethod(methodName).Invoke(null, arguments);
where typeName is the name of the type as a string, methodName is the name of the method as a string, and arguments is an array of objects containing the arguments to call the method with.
First you need to get the Type (by iterating on the assembly using reflection)
see this link for details: http://msdn.microsoft.com/en-us/library/system.reflection.propertyinfo.aspx
or use
Assembly.GetType
once you have the type in hand you can iterate over members using reflection or
MethodInfo method = typeof(MyClass).GetMethod("MyMethod");
then you can use MethodInfo.Invoke and pass arguments to invoke the method when you want to invoke it.
System.Reflection.Assembly info = typeof(System.Environment).Assembly;
Type t = info.GetType("System.Environment");
MethodInfo m = t.GetMethod("GetFolderPath");
object result = m.Invoke(null, arguments);
What you are doing here is reflecting on the type named Environment and using the GetPropery and GetGetMethod methods to get the get method of the Environment.CurrentDirectory property like so;
var getMethod = typeof(Environment).GetProperty("CurentDirectory", BindingFlags.Public | BindingFlags.Static).GetGetMethod();
var currentDirectory = (string)getMethod.Invoke(null, null);
Calling the get method of a property returns it's value and is equivilent to;
var value = Environment.CurrentDirectory;
Here is a basic outline of what you would do:
Scan all the objects in the current AppDomain - find the one that matches what you know the class name to be
Get the static method with the name you know on that object
Dynamically invoke it.
Edit: This will work if you do not know the namespace of the static class. Otherwise use Daniel Brückner's solution as its much simpler.