I'm able to compile code that includes this:
OperationDelegate myOpDelegate;
static OperatorDefinition[] definitions ={
new OperatorDefinition("+",2,3,true, new OperationDelegate(OperationAdd)),
};
delegate double OperationDelegate(double[] args);
static double OperationAdd(double[] args)
{
return args[0] + args[1];
}
but I think my code would look cleaner if I could do something more like this:
OperationDelegate myOpDelegate;
static OperatorDefinition[] definitions ={new OperatorDefinition("+",2,3,true, new OperationDelegate({return args[0]+args[1]}))};
delegate double OperationDelegate(double[] args);
because I want to define everything about each OperatorDefinition in a single place, rather than defining the functions separately. Is there some way to do this in C#?
(any other criticism about my code would be welcome, too)
Look into anonymous methods... for example this: C# - Anonymous delegate
You can use Lambda expressions as from .Net 3.5:
static OperatorDefinition[] definitions ={
new OperatorDefinition("+",2,3,true,
args => args[0] + args[1])
};
In your OperatorDefinition constructor, last parameter should be of type Func<double[],double>
See:
http://msdn.microsoft.com/en-us/library/bb397687.aspx
Related
Lets say I have:
static void Foo(string s, int i){//some implementation}
static void Bar(string s){//some other implementation}
delegate void Del(string s);
obviously, it is possible to go:
Del d = Bar
but is it possible to do something like:
Del d2 = Foo(7); //just takes in string s as the only parameter;
I'm wondering if there is a way to redefine some of the parameters so that the leftover parameters match the signature of the delegate.
Is this possible without having to define an intermediate method like this:
static void IntermediateMethod(string s){ return Foo(s, 7);}
`
I think this is the closest I can get to what I wanted.
Del d2 = delegate(string s){Foo(s,7);};
This basically achieves my goal since the method is anonymous and you don't need an intermediate method.
I am trying to develop a template engine in c# and in my concept I will need to read to read methods as well as parameters from text files.This shows something could be done , but it does not work if the parameter is also read from the text.Is there a way to achieve this?
private static void Main(string[] args)
{
string returnValue = Execute("AMethod(\"Hello\")");
//the result in retunValue is same as from code commented below:
// string returnValue= AMethod("Hello");
}
public static string AMethod(string parameter)
{
return "xyz" + parameter;
}
The problem here is how to write the Execute Method
The link you provided has the answer you are looking for. Look at the line
object[] parametersArray = new object[] { "Hello" };
and change it to
object[] parametersArray = new object[] { parameter };
There are really 3 ways to accomplish what you are trying to accomplish:
Reflection (this is what is explained in the article you reference)
Reflection.Emit
Dynamic compilation
2 & 3 are more complicated and heavy weight, but depending on the syntax you are trying to achieve in your template engine, one of those might be the best way to go. Reflection requires that you handle each aspect of the invocation--binding to the correct method, passing arguments as arrays, etc. Dynamic compilation would allow you to take a line a C# code formatted exactly how you would write it in a .cs file, compile it to a new method, load the assembly, and execute it. This is all a bit of a hassle, so if you aren't married to having to execute a string that looks like AMethod("Hello"), I highly recommend the reflection route.
Here is an example of what you are trying to achieve with pure reflection:
private static void Main(string[] args)
{
string methodName = "AMethod";
object[] parameters = new object [] {"Hello", "foo"};
MethodInfo method = typeof(Program).GetMethod(methodName, BindingFlags.Static);
string returnValue = (string)method.Invoke(null, parameters);
}
public static string AMethod(string parameter1, string parameter2)
{
return "xyz" + parameter1 + "abc" + parameter2;
}
For examples of 2 & 3, you can take a look at this question: Compiling code dynamically using C#
Part of my software is using reflection. The issue I am having is that while I can get the type of the property, I cannot convert the string value using the Type from the PropertyInfo. This is the reason why i am using t in the sample code.
The below code demonstrates the issue with the error message as a code comment. The syntax error is on the t. how can I fix this problem? thanks
class Program
{
static void Main(string[] args)
{
Type t = typeof(Letters);
Letters letter = "A".ToEnum<t>(); //-- Type or namespace expected.
}
}
public enum Letters { A, B, C }
//-- This is a copy of the EmunHelper functions from our tools library.
public static class EnumExt
{
public static T ToEnum<T>(this string #string)
{
int tryInt;
if (Int32.TryParse(#string, out tryInt)) return tryInt.ToEnum<T>();
return (T)Enum.Parse(typeof(T), #string);
}
public static T ToEnum<T>(this int #int)
{
return (T)Enum.ToObject(typeof(T), #int);
}
}
Solution:
The following works because when the value is set using reflection, the actual type of Enum is accepted. Where myObject.Letter = result is not.
Type t = currentProperty.PropertyType;
Enum result = Enum.Parse(t, #string) as Enum;
ReflectionHelper.SetProperty(entity, "LetterPropertyName", result);
Thank you all for your help.
Enum.Parse(t, #string) as Enum;
That accomplishes the same thing as the solution you posted.
To be able to call a generic method, the type must be known at compile time. Your use is invalid syntax.
To be able to call your method, you'll have to use reflection to get a reference to the correct generic function so you may call it.
public static object ToEnum(this string s, Type type)
{
var eeType = typeof(EnumExt);
var method = eeType.GetMethod("ToEnum", new[] { typeof(string) })
.MakeGenericMethod(type);
return method.Invoke(null, new[] { s });
}
Then you could call it:
Letters letter = (Letters)"A".ToEnum(t);
p.s., I strongly urge you to change your variable names to something else. Just because you can name your variables as keywords, doesn't mean that you should.
I'm not an expert with reflection, but this works:
static void Main(string[] args)
{
Type t = typeof(Letters);
MethodInfo info = typeof(EnumExt).GetMethod("ToEnum", new Type[] { typeof(string) });
var method = info.MakeGenericMethod(new Type[] { t });
var result = (Letters)method.Invoke(null, new [] { "A" });
Console.ReadLine();
}
I think your question can be understood in two ways:
i) you want to fix a syntax error
ii) you need a working implementation for the function you provide
For i), I would suggest you to change:
Letters letter = "A".ToEnum<t>()
into
Letters letter = "A".ToEnum<Letters>()
because generics are solved at compile time, hence you cannot use variables as parameters.
For ii), you may change the way you provide the type argument, from "generic" argument to "normal" argument (as proposed by Jeff Mercado). By doing so the prototype of your function becomes:
public static T ToEnum(this string #string, Type t)
I conclude with two remarks:
reflection is VERY slow to my experience. I once wrote an assembly parser making extensive use of reflection on enums for register names. It used to run for minutes (which used to make VS debugger complain about non-responsiveness) when an equivalent version without any reflection used to execute in less than 10 seconds.
as Jeff Mercado pointed out, I cannot see any good reason for you to use the same vocable for type names and variable names
Action doesnt seem to support params string[] as a param so i wrote
delegate void WriteFn(string s, params string[] ls);
i have this function
void blah(WriteFn Write, string fmt, params string[] a)
Now i would like to write an function but i cant seem to figure the syntax out. It something like
{
var sw = ...
blah(new WriteFn(s, ls) { sw.write(s, ls); }, fmt, a);
//not what i want to do but close enough. remember sw isnt a param in WriteFn
How do i write this?
Your question is not clear. Are we suppose to guess that sw is a StreamWriter? If so, it looks like this would work:
blah((s, ls) => sw.Write(s, ls), fmt, a);
I think you can't do this because variable argument lists is NOT compatible with anonymous methods, according to MSDN.
Why won't this work?
public static int[] GetListOfAllDaysForMonths()
{
static int[] MonthDays = new int[] {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31};
return MonthDays;
}
I had to move the variable declaration outside of the method:
static int[] MonthDays = new int[] {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31};
public static int[] GetListOfAllDaysForMonths()
{
return MonthDays;
}
Also, so by creating it this way, we only have one instance of this array floating around in memory? This method sits inside a static class.
C# doesn't support static locals at all. Anything static needs to be a member of a type or a type itself (ie, static class).
Btw, VB.Net does have support for static locals, but it's accomplished by re-writing your code at compile time to move the variable to the type level (and lock the initial assignment with the Monitor class for basic thread safety).
[post-accept addendum]
Personally, your code sample looks meaningless to me unless you tie it to a real month. I'd do something like this:
public static IEnumerable<DateTime> GetDaysInMonth(DateTime d)
{
d = new DateTime(d.Year, d.Month, 1);
return Enumerable.Range(0, DateTime.DaysInMonth(d.Year, d.Month))
.Select(i => d.AddDays(i) );
}
Note also that I'm not using an array. Arrays should be avoided in .Net, unless you really know why you're using an array instead of something else.
You can only create static variables in the class/struct scope. They are static, meaning they are defined on the type (not the method).
This is how C# uses the term "static", which is different from how "static" is used in some other languages.
What would be the scope of that static variable declared within the method? I don't think CLR supports method static variables, does it?
Well, apart from it not being supported, why would you want to? If you need to define something inside a method, it has local scope, and clearly doesn't need anything more than that.