How to treat function as string? - c#

just I want to ask is it possible to Call function as ToUpper or ToLower() as string for example f.Name.Replace(" ", "_").ToLower()".ToLower()" or "ToUpper" for example if user select convert file name to ToLower() from dropdown list.it will take the value 'ToLower' and added to in of the function and executed the function call

Well, not cleanly. You could use reflection to find the method but you'd have to know the exact type that the function will be applied to since you won't get sophisticated binding like you do at compile-time. Plus you'll be limited to one method signature (in this case, no input parameters and returns a string).
To support any string function with that signature you could use:
string val = f.Name.Replace(" ", "_").ToLower();
string strCommand = "ToUpper";
MethodInfo theMethod = typeof(string).GetMethod(strCommand,new Type[] {});
string result = (string)(theMethod.Invoke(val,null));
But a simple switch seems cleaner and safer here.

The conditional operator (?:) would probably be a better option here
var fileName = f.Name.Replace(" ", "_");
fileName = ddl.SelectedValue == "ToLower" ? fileName.ToLower() : fileName.ToUpper();
Using Reflection for something as trivial as this is pretty unnecessary.

If you know the methods you want to call before, you can register them in a dictionary (key = name of the function or something user friendly, value = function that performs the conversion):
var dict = new Dictionary<string, Func<string, string>>();
dict.Add("Lowercase", x => x.ToLower());
dict.Add("Uppercase", x => x.ToUpper());
You can bind the drop down list to the dictionary (text = Key, value = Value) and perform the conversion as follows (ddl is the name of the DropDownList):
var f = (Func<string, string>)ddl.SelectedValue;
var convStr = f(inputStr);

You can create a defined dictionary of functions, which you can access by name of the action. You will get rid of any conditional statements and of all reflection. Example is given below:
var actions = new Dictionary<string, Func<string, string>>()
{
//keys may have other, human-readable values
{"ToLower", s => s.ToLower()},
{"ToUpper", s => s.ToUpper()}
};
//you will receive this from drop down list, it's the name of the action
var userSelectedOption = "ToUpper";
//string that you want to process
var myString = "some other user input";
//selecting appropriate action and passing myString to it
var transformedString = actions[userSelectedOption](myString);
//prints "SOME OTHER USER INPUT"
Console.WriteLine(transformedString);

Using reflection, you can call a methods using a string:
String ToLower = "ToLower";
String SometString = "This Is My String";
Type stringType = typeof(String);
// Get the overload of ToLower that takes no parameters
MethodInfo method = stringType.GetMethod(ToLower, System.Type.EmptyTypes);
// Invoke the method with no parameters
String newString = (String)method.Invoke(SometString, null);
MessageBox.Show(newString);

If I have understood your question correctly, you want to call a method based on a string.
You can use reflection, which is a topic in and of itself, but to get you started you can do something like:
MethodInfo chosenMethod = typeof(string).GetMethod(methodName, Types.EmptyTypes);
chosenMethod.Invoke(stringToModify, new object[]{});
But if it is a very limited set of functions you want to expose, you should just do a switch statement over the user input:
switch(methodName)
{
case "ToLower":
stringToModify.ToLower();
break;
...

You can use a simple switch statement:
switch (value) // Assuming value is of type SomeEnum
{
case SomeEnum.ToLower:
return f.ToLower()
case SomeEnum.ToUpper:
return f.ToUpper();
default:
//Do the Default
break;
}
This is how you parse what you get from the UI:
public static T ParseEnum<T>( string value )
{
return (T) Enum.Parse( typeof( T ), value, true );
}

Perhaps you might need to avoid limitations is sort of a Runtime intepreter of C#, like eval() function in JavaScript, which is not easily nor trivial to implement, but there is a good library out there called C# Eval ( http://csharp-eval.com/Download.php ) that uses Reflection internally of course. It is heavier but more effective for this, or even for much more complex escenarios.
You might use it in this way for example:
class Person
{
public string Name;
public string Process(string expression)
{
return CsEval.Eval(this, expression);
}
}
And then might call it:
var f = new Person();
f.Name = "John";
f.Name = f.Process("Name.Replace(" ", "_").ToLower()");
Of course this is just an example of how it evaluate what is in the string, as you can see you just need to pass a "context" where the expression is going to mean something, which in this case is the current class ("this").

Related

C# how do I pass optional parameters as a collection?

Assuming I have 3rd party MethodA(type1 paramName1 = null, type2 paramName2 = null,...., nonNullAbleSuchAsInt paramName10 = 123).
And I want do the following by calling the same MethodA using the provided data given by the user. User may give me data for paramName2 and paramName4, or some other permutations such as [paramName2, paramName3, paramName5, paramName7] and etc.
if(user gives me data for paramName2 and nothing else)
{
MethodA(paramName2=userData2)
}
else if(user give me data for paramName2, paramName3, and nothing else)
{
MethodA(paramName2=userData2, paramName3=userData3)
}
else if(user give me data for paramName2, paramName4, and nothing else)
{
MethodA(paramName2=userData2, paramName4=userData4)
}
else if(user give me data for paramName2, paramName3, paramName4, and nothing else)
{
MethodA(paramName2=userData2, paramName3=userData3, paramName4=userData4)
}
... repeat for all permutations.
But, that's so many duplicated code.
I want to do the following. How do I do it?
MagicStorage<MethodA_Declaration> magicArgs = new MagicStorage<MethodA_Declaration>();
if(user gives me data for paramName1)
{
magicArgs.Add(paramName1, userData1);
}
if(user gives me data for paramName2)
{
magicArgs.Add(paramName2, userData2);
}
... repeat
if(user gives me data for paramName10)
{
magicArgs.Add(paramName10, userData10);
}
MethodA(magicArgs);
And if I made a mistake like userData10 is not the same type needed by paramName10, I get editor and compiler error.
Is this possible? I don't want to make a method call for all the permutations of user input data. There would be too much code to manage.
Given
MethodA(type1 paramName1 = null, type2 paramName2 = null, int paramName10 = 132).
Usage
public class data
{
public type1 ParamName1 {get;set;}
public type2 paramName2 {get;set;}
// initalize with what ever default the method takes as optional
public int paramName10 {get;set;} = 123;
}
...
// pass in all paramaters, dont both about ifs
// we can do this, because you have already figured out the defaults
// from the signature
MethodA(data.ParamName1, data.paramName2, data.paramName10);
One way would be to use reflection to call the method with an ordered array of parameters, where the user specified values are used where possible and Type.Missing used where no value was specified:
public static object InvokeWithOrderedParameters(object instance, string methodName,
IDictionary<string, object> namedParameters)
{
// Get the method to invoke
var method = instance.GetType().GetMethod(methodName);
// Get an array of ordered parameter values based on the specified named
// parameters, with a default value of "Type.Missing" for any missing names
var orderedParams = method.GetParameters().Select(param =>
{
object value;
// Set the value from our dictionary, or if that fails use "Type.Missing"
if (!namedParameters.TryGetValue(param.Name, out value))
{
value = Type.Missing;
}
return value;
}).ToArray();
// Invoke the method with the ordered parameters and return the value
return method.Invoke(instance, orderedParams);
}
With this method, we can pass the instance of our type, the name of the method to invoke, and a Dictionary<string, object> of named parameters and their values, and it will return the result of calling that method with the parameters that we specified.
As an example, here's a method that has default values for all it's parameters:
public class ThirdParty
{
public string MethodA(string arg1 = "defaultArg1", string arg2 = "defaultArg2",
string arg3 = "defaultArg3")
{
return $"{arg1}, {arg2}, {arg3}";
}
}
And we can use our reflection method to call it with as many named parameters as we like. Below I'm just giving a value for the second parameter:
public static void Main(string[] args)
{
var namedParameters = new Dictionary<string, object>
{
{"arg2", "custom Arg 2 value"}
};
var instance = new ThirdParty();
var result = InvokeWithOrderedParameters(instance, "MethodA", namedParameters);
Console.WriteLine(result.ToString());
GetKeyFromUser("\nDone! Press any key to exit...");
}
Output
As you can see, the value we specified was passed, and the default values were used where we didn't specify anything:
You can make it somewhat more readable using the switch support for pattern matching.
And of course you can replace any switch with a Dictionary and a loop, as long as the value has place for a function delegate. Of course in this case, the Key might need to have a delegate too.
Those would make the code more readable, but can not avoid the write work.
Beyond that, there is only moving the resolution of the function calls out of compile time and into runtime. A step I am not a friend off and thus have little experience in.
You can have something like
int param1 = default(int);
double param2 = default(double);
MyClass param3 = default(MyClass);
....
int param10 = 123;
ReadUserData(out param1, out param2, out param3, ..., out param10)
Then call MethodA:
MethodA(param1, param2, param3, ..., param10)
NOTE: Starting with C# 7.0 (I think) when using out parameters there is a sugar that let you declare the variables with the method call (so you don't have to declare them one by one), for example, the call to ReadUserData can be done as:
ReadUserData(out int param1, out double param2, out MyClass param3, ..., out int param10)

Get parameters from lambda Expression

I am not very familiar with lambda expressions. So I have the following expression:
EnabledPropertySelector = l => l.FranchiseInfo.ExternalSystemType == ExternalSystemTypes.Master
And two properties:
public string VisibilityPropertyName { get; set; }
public object VisibilityPropertyValue { get; set; }
I want to extract some data from the expression so in the end I can get the values of the two properties:
VisibilityPropertyName == 'FranchiseInfo.ExternalSystemType';
VisibilityPropertyValue == ExternalSystemTypes.Master;
VisibilityPropertyName is always a string. This is the name of the property.
VisibilityPropertyValue can be of any type.
EDIT:
I have a lot of properties. Some of them are dependent on other properties. For every single property I have to manually write the name and the value of the parent property:
{ VisibilityPropertyName = 'FranchiseInfo.ExternalSystemType', VisibilityPropertyValue = ExternalSystemTypes.Master, EnabledPropertySelector = l => l.FranchiseInfo.ExternalSystemType == ExternalSystemTypes.Master}
Instead of writing all this I want to write only the expression and populate the properties from it.
This is the declaration of the expresion:
Expression<Func<TEntity, bool?>> EnabledPropertySelector
First off all, you need an Expression. What's the type of EnabledPropertySelector? It'll need to be something like Expression<Func<T, bool>> where T is whatever the type of "l" in your example is.
If you already have an Expression then you can use the Expression API to extract whatever you need:-
var body = EnabledPropertySelector.Body as BinaryExpression;
var left = body.Left as PropertyExpression;
var outerMemberName = left.Member.Name;
var innerMemberName = (left.Expression as PropertyExpression).Member.Name
VisibilityPropertyName = innerMemberName + "." + outerMemberName;
var right = body.Right as PropertyExpression;
var rightValueDelegate = Expression.Lambda<Func<object>>(right).Compile();
VisibilityPropertyValue = rightValueDelegate();
etc.
I really recommend doing some reading to properly grok the expression API before diving in though; there are a lot of corner cases depending on how flexible you need to be. E.g. is the expression always of the form parameter.Property.Property == constant? It gets really complicated really quickly, so you'll want a solid understanding of the fundamentals before trying to handle any real-world cases.
There's a reasonable introduction to expression trees on MSDN, but some focused googling might get you a better understanding quicker.
You can use Funciton and Action class, I'm not very sure of what you want be able to do, but I can give an tip.
Functions returns a value:
Function<InputType1,InputType2,ResultType> functionVariableName;
Usage:
functionVariableName = (param1, param2) => {
//...process both params
return result;
};
Actions, do not return values:
Action<InputType1,InputType2> actionVariableName;
Usage:
actionVariableName= (param1, param2) => {
//...process both params
};
If the lambda expression is simple (one line, with out if expression) you can make the lambda with out {}:
functionVariableName = (param1, param2) => //process values and result;
Hope this helps...
if you want to create an IEnumerable where the two properties are equal:
var results = EnabledPropertySelector.Where(l => l.FranchiseInfo.ExternalSystemType ==
ExternalSystemTypes.Master.ToString());

Extension method with dynamic named parameters

I'm currently writing an extension to replace the normal string.Format with my FormatNamed-function.
So far I have got this code, but I want to change the way to input the parameters
void Main()
{
string sql = "SELECT {fields} FROM {table} WHERE {query}"
.FormatNamed(new { fields = "test", table = "testTable", query = "1 = 1" });
Console.WriteLine(sql);
}
public static class StringExtensions
{
public static string FormatNamed(this string formatString, dynamic parameters)
{
var t = parameters.GetType();
var tmpVal = formatString;
foreach(var p in t.GetProperties())
{
tmpVal = tmpVal.Replace("{" + p.Name + "}", p.GetValue(parameters));
}
return tmpVal;
}
}
Not the prettiest of replaces, but it does the job.
Anyway. I want to change so I can execute it with
.FormatName(field: "test", table: "testTable", query: "1 = 1");
Is there any way I can do this? I have tried googling for dynamic named parameters with no good results.
You won't be able to specify an arbitrary number of dynamic, named parameters. that's just not something that C# supports. Your existing code seems okay to me, although I don't see the need for the dynamic parameter. This will work just as well:
public static string FormatNamed(this string formatString, object parameters)
{
var t = parameters.GetType();
var tmpVal = formatString;
foreach(var p in t.GetProperties())
{
tmpVal = tmpVal.Replace("{" + p.Name + "}", p.GetValue(parameters));
}
return tmpVal;
}
And then calling it as:
string sql = "SELECT {fields} FROM {table} WHERE {query}"
.FormatNamed(new { fields = "test", table = "testTable", query = "1 = 1" });
Although I really wouldn't advise using this sort of method for constructing SQL (it won't save you from SQL injection attacks at all), the method itself is sound.
I have tried googling for dynamic named parameters with no good results
That's because the capability does not exist. Think about it - how would the function know what to do if the parameters and their names were not known at compile time? The closest thing I can think of is using params which gives you an array of values, but they must all be the same type, and you can still access them by a given name (and index value).
I'd stick with the method you're currently using:
.FormatName(new {field = "test", table = "testTable", query = "1 = 1"});
That creates an anonymous type with the properties specified, which should work fine with your existing code. Plus it's only a few extra characters to type.
Also note that dynamic doesn't buy you anything here since it's used to access properties directly without using reflection. Since you're using reflection to get the propeties you can just use object.

Any way to get the type of Tuple<> item(s)

where the def is
IEnumerable<Tuple<string, double>> GetValues()
{
....
yield return new Tuple<string,double>(dataRow["<field>"].ToString(),
(double)Convert.ChangeType(dataRow["<field>"], typeof(double)));
....
// and more code similar to above based on other custom logic
}
as you can see, that,s a lot of casting/coerc'ng to double
it may still change back to string or to other datatypes
wondering if there is a way to get the datatypes of Tuple defined in the signature so i can create some generic helper and not worry about missing some conversion somewhere
It should be possible with Reflection? i hope !
If this is the DataRow class, you have a nice extension method called Field for this.
IEnumerable<Tuple<T1, T2>> GetValues<T1, T2>(String field1, String field2)
{
....
yield return new Tuple<T1,T2>(dataRow.Field<T1>("<field>"),
dataRow.Field<T2>("<field>"));
....
}
If you have an instance of the Tuple you can get the generic type parameters via reflection:
var x = Tuple.Create<int, string>(0, "test");
var y = x.GetType().GetGenericArguments();
y[0].Name = "System.Int32";
You can get this same information at compile-time using "typeof()", or at runtime using reflection, like so:
public Tuple<string, double> DoSomething()
{
var y = typeof(Tuple<string, double>).GetGenericArguments();
var z = MethodBase.GetCurrentMethod().ReturnType.GetGenericArguments();
}
I don't think this is really going to help you; you can't bind the type information obtained at run-time to generic parameters at compile type, so you aren't saving yourself a whole lot of work. You will still end up having to specify the data types repeatedly somewhere.
Chris Shain's answer (the Field<T> method) really is the way to go here.
Not sure, but could the following be of help?
bool bStringResult = false, bDoubleResult = false;
string sString = string.Empty;
double dDouble = 0;
Tuple<string, double> tTuple = Tuple.Create(sString, dDouble);
if (tTuple.Item1.GetType() == typeof(string)) bStringResult = true;
if (tTuple.Item2.GetType() == typeof(double)) bDoubleResult = true;
Console.WriteLine($"String: {bStringResult}, Double: {bDoubleResult}");
Result : String: True, Double: True

Get value of c# dynamic property via string

I'd like to access the value of a dynamic c# property with a string:
dynamic d = new { value1 = "some", value2 = "random", value3 = "value" };
How can I get the value of d.value2 ("random") if I only have "value2" as a string? In javascript, I could do d["value2"] to access the value ("random"), but I'm not sure how to do this with c# and reflection. The closest I've come is this:
d.GetType().GetProperty("value2") ... but I don't know how to get the actual value from that.
As always, thanks for your help!
Once you have your PropertyInfo (from GetProperty), you need to call GetValue and pass in the instance that you want to get the value from. In your case:
d.GetType().GetProperty("value2").GetValue(d, null);
public static object GetProperty(object target, string name)
{
var site = System.Runtime.CompilerServices.CallSite<Func<System.Runtime.CompilerServices.CallSite, object, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, name, target.GetType(), new[]{Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0,null)}));
return site.Target(site, target);
}
Add reference to Microsoft.CSharp. Works also for dynamic types and private properties and fields.
Edit: While this approach works, there is almost 20× faster method from the Microsoft.VisualBasic.dll assembly:
public static object GetProperty(object target, string name)
{
return Microsoft.VisualBasic.CompilerServices.Versioned.CallByName(target, name, CallType.Get);
}
Dynamitey is an open source .net std library, that let's you call it like the dynamic keyword, but using the a string for the property name rather than the compiler doing it for you, and it ends up being equal to reflection speedwise (which is not nearly as fast as using the dynamic keyword, but this is due to the extra overhead of caching dynamically, where the compiler caches statically).
Dynamic.InvokeGet(d,"value2");
The easiest method for obtaining both a setter and a getter for a property which works for any type including dynamic and ExpandoObject is to use FastMember which also happens to be the fastest method around (it uses Emit).
You can either get a TypeAccessor based on a given type or an ObjectAccessor based of an instance of a given type.
Example:
var staticData = new Test { Id = 1, Name = "France" };
var objAccessor = ObjectAccessor.Create(staticData);
objAccessor["Id"].Should().Be(1);
objAccessor["Name"].Should().Be("France");
var anonymous = new { Id = 2, Name = "Hilton" };
objAccessor = ObjectAccessor.Create(anonymous);
objAccessor["Id"].Should().Be(2);
objAccessor["Name"].Should().Be("Hilton");
dynamic expando = new ExpandoObject();
expando.Id = 3;
expando.Name = "Monica";
objAccessor = ObjectAccessor.Create(expando);
objAccessor["Id"].Should().Be(3);
objAccessor["Name"].Should().Be("Monica");
var typeAccessor = TypeAccessor.Create(staticData.GetType());
typeAccessor[staticData, "Id"].Should().Be(1);
typeAccessor[staticData, "Name"].Should().Be("France");
typeAccessor = TypeAccessor.Create(anonymous.GetType());
typeAccessor[anonymous, "Id"].Should().Be(2);
typeAccessor[anonymous, "Name"].Should().Be("Hilton");
typeAccessor = TypeAccessor.Create(expando.GetType());
((int)typeAccessor[expando, "Id"]).Should().Be(3);
((string)typeAccessor[expando, "Name"]).Should().Be("Monica");
Much of the time when you ask for a dynamic object, you get an ExpandoObject (not in the question's anonymous-but-statically-typed example above, but you mention JavaScript and my chosen JSON parser JsonFx, for one, generates ExpandoObjects).
If your dynamic is in fact an ExpandoObject, you can avoid reflection by casting it to IDictionary, as described at http://msdn.microsoft.com/en-gb/library/system.dynamic.expandoobject.aspx.
Once you've cast to IDictionary, you have access to useful methods like .Item and .ContainsKey
The GetProperty/GetValue does not work for Json data, it always generate a null exception, however, you may try this approach:
Serialize your object using JsonConvert:
var z = Newtonsoft.Json.JsonConvert.DeserializeObject(Convert.ToString(request));
Then access it directly casting it back to string:
var pn = (string)z["DynamicFieldName"];
It may work straight applying the Convert.ToString(request)["DynamicFieldName"], however I haven't tested.
d.GetType().GetProperty("value2")
returns a PropertyInfo object.
So then do
propertyInfo.GetValue(d)
To get properties from dynamic doc
when .GetType() returns null, try this:
var keyValuePairs = ((System.Collections.Generic.IDictionary<string, object>)doc);
var val = keyValuePairs["propertyName"].ToObject<YourModel>;
This is the way i ve got the value of a property value of a dinamic:
public dynamic Post(dynamic value)
{
try
{
if (value != null)
{
var valorCampos = "";
foreach (Newtonsoft.Json.Linq.JProperty item in value)
{
if (item.Name == "valorCampo")//property name
valorCampos = item.Value.ToString();
}
}
}
catch (Exception ex)
{
}
}
Some of the solutions were not working with a valuekind object that I obtained from a json string, maybe because I did not have a concrete type in my code that was similar to the object that I would obtain from the json string, so how I went about it was
JsonElement myObject = System.Text.Json.JsonSerializer.Deserialize<JsonElement>(jsonStringRepresentationOfMyObject);
/*In this case I know that there is a property with
the name Code, otherwise use TryGetProperty. This will
still return a JsonElement*/
JsonElement propertyCode = myObject.GetProperty("Code");
/*Now with the JsonElement that represents the property,
you can use several methods to retrieve the actual value,
in this case I know that the value in the property is a string,
so I use the GetString method on the object. If I knew the value
was a double, then I would use the GetDouble() method on the object*/
string code = propertyCode.GetString();
That worked for me
In .Net core 3.1 you can try like this
d?.value2 , d?.value3
Similar to the accepted answer, you can also try GetField instead of GetProperty.
d.GetType().GetField("value2").GetValue(d);
Depending on how the actual Type was implemented, this may work when GetProperty() doesn't and can even be faster.
In case you have a dynamic variable such as a DapperRow for example you can first build up an ExpandoObject, then cast the Expando into an IDictionary<string, object>. From then on, getting a value via the name of a property is possible.
Helper method ToExpandoObject:
public static ExpandoObject ToExpandoObject(object value)
{
IDictionary<string, object> dapperRowProperties = value as IDictionary<string, object>;
IDictionary<string, object> expando = new ExpandoObject();
if (dapperRowProperties == null)
{
return expando as ExpandoObject;
}
foreach (KeyValuePair<string, object> property in dapperRowProperties)
{
if (!expando.ContainsKey(property.Key))
{
expando.Add(property.Key, property.Value);
}
else
{
//prefix the colliding key with a random guid suffixed
expando.Add(property.Key + Guid.NewGuid().ToString("N"), property.Value);
}
}
return expando as ExpandoObject;
}
Sample usage, I have marked in bold the casting which gives us access in the example, I have marked the important bits with the ** letters:
using (var transactionScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
foreach (var dynamicParametersForItem in dynamicParametersForItems)
{
var idsAfterInsertion = (await connection.QueryAsync<object>(sql, dynamicParametersForItem)).ToList();
if (idsAfterInsertion != null && idsAfterInsertion.Any())
{
**var idAfterInsertionDict = (IDictionary<string, object>) ToExpandoObject(idsAfterInsertion.First());**
string firstColumnKey = columnKeys.Select(c => c.Key).First();
**object idAfterInsertionValue = idAfterInsertionDict[firstColumnKey];**
addedIds.Add(idAfterInsertionValue); //we do not support compound keys, only items with one key column. Perhaps later versions will return multiple ids per inserted row for compound keys, this must be tested.
}
}
}
In my example, I look up a property value inside a dynamic object DapperRow and first convert the Dapper row into an ExpandoObject and cast it into a dictionary property bag as shown and mentioned in other answers here.
My sample code is the InsertMany method for Dapper extension I am working on, I wanted to grab hold of the multiple ids here after the batch insert.
Use dynamic with Newtonsoft.Json.JsonConvert.DeserializeObject:
// Get JSON string of object
var obj = new { value1 = "some", value2 = "random", value3 = "value" };
var jsonString = JsonConvert.SerializeObject(obj);
// Use dynamic with JsonConvert.DeserializeObject
dynamic d = JsonConvert.DeserializeObject(jsonString);
// output = "some"
Console.WriteLine(d["value1"]);
Sample:
https://dotnetfiddle.net/XGBLU1

Categories

Resources