I'm trying to write a couple extensions for some types I'm working with. The base type is 'InputField'. 'ListField' inherits from 'InputField'. I'll show what I'm trying to do:
public static void LoadInputField(this InputField input, CustomField field)
{
SetValues(ref input, field);
}
public static void LoadInputField(this ListField input, CustomField field)
{
SetValues(ref input, field);
var optionItems = (from o in field.CustomFieldOptions
select new ListItem(o.OptionLabel, o.CustomFieldOptionId.ToString()));
input.AddChoices(optionItems.ToList());
}
private static void SetValues(ref InputField input, CustomField field)
{
input.CustomFieldId = field.CustomFieldId;
input.ResponseTitle = field.ColumnName;
input.Prompt = field.ColumnCaption;
input.DisplayOrder = field.SortOrder;
input.Required = !string.IsNullOrEmpty(field.ColumnRequiredMessage);
input.ErrorClass = "text-danger";
if (input.Required)
input.RequiredMessage = field.ColumnRequiredMessage;
}
The extension for the ListField type errors at SetValues(ref input, field);. The message says, 'The 'ref' argument type doesn't match parameter type.'
Perhaps this isn't the best way to do this, but I'm open to options.
You can cast it on a local variable before you call the method:
InputField inputField = (InputField)input;
SetValues(ref inputField, field);
Apart from that i don't understand why you need ref, it works without casting if it's not ref. C# requires that any ref parameters be of the exact type.
As per the suggestions in the comments, I dropped ref and the code works.
Related
I am making a windows application.
At first I declared var and it contains another class method.
var ExtList = ExtTarget.GetExtTargets();
And GetExtTargets() is like this
public static List<ExtTarget> GetExtTargets()
{
var dt = SqlHelper.ExecuteDataTable(QueryHelper.ConnectionString,
#"
SELECT [seq],[SourceKind],[ExtKind],[DBKind],[ConnectionString]
,[FilePath],[TableName],[FileKind],[RowSplitter],[ColumnSplitter]
,[Title],[GroupName],[SyncOrder],[RepeatKind],[RepeatMonth]
,[RepeatDay],[RepeatHour],[RepeatMin],[RepeatWeek],[RepeatWeekNum]
,[LastSyncExecDate]
FROM [ExtTarget]
order by GroupName,SyncOrder");
return dt.Rows.Cast<DataRow>().Select<DataRow, ExtTarget>(a => ExtTarget.RowToModel(a)).ToList();
}
Then, I used it to foreach and then I want to pass Ext to another method's parameter.
Code is like this.
public void ProcessExtSync(object obj)
{
while (IsProcessGoing)
{
Thread.Sleep(ThreadDelay);
if (!IsProcessGoing) return;
var ExtList = ExtTarget.GetExtTargets();
foreach (var Ext in ExtList) // I want to use this Ext as parameter
{
while (IsSourceSyncGoing)
{
Thread.Sleep(ThreadDelay);
}
IsExtSyncGoing = true;
bool ExtSyncForceToRun = ConfigSettingHelper.Instance.IsServiceConfig(Words.ExtSyncForceToRun);
bool ExtSyncForceToRunOnlyError = ConfigSettingHelper.Instance.IsServiceConfig(Words.ExtSyncForceToRunOnlyError);
bool ExtSyncNeedToRun = ConfigSettingHelper.Instance.GetNextExecutingTime(Ext) < DateTime.Now;
if (ExtSyncForceToRun || ExtSyncNeedToRun)
{
//I want to pass Ext as parameter to this method
ServiceProcess.Instance.SyncExt();
if (ExtSyncForceToRun)
{
ConfigSettingHelper.Instance.SetServiceConfig(Words.ExtSyncForceToRun, false);
}
if (ExtSyncForceToRunOnlyError)
{
ConfigSettingHelper.Instance.SetServiceConfig(Words.ExtSyncForceToRunOnlyError, false);
}
}
if (!IsProcessGoing) return;
}
IsExtSyncGoing = false;
}
}
How can I modify that code? Please help me.
var is just a shortcut way of implicitly typing a variable. It saves some typing, but sometimes makes code harder to read when the reader can't determine the type. The compiler can figure out the strong type, though (or you'll get a compiler error), and if you hover over it in Visual Studio, the compiler will tell you the actual type.
With that out of the way, all you need to do is make sure that the method you want to pass your variable to takes in the type that you want to pass it (remember the type is not var, but in your case it is an ExtTarget).
The method you're calling should have a signature similar to this (although it may return any type):
public void SyncExt(ExtTarget extTarget)
{
// Implementation code here
}
Then in your code above you can call:
ServiceProcess.Instance.SyncExt(Ext);
I've created a generic delegate and I want to assign to it a function without any arguments.
Is it possible?
Here is what I tried so far:
class Program
{
public delegate void TemplateDel<T>(T item);
public static void fWriteLetters(char[] p_cLetters)
{
for (int i = 0; i < p_cLetters.Length; i++)
Console.WriteLine(p_cLetters[i]);
}
void fNoArg()
{
Console.WriteLine("No arguments!");
}
static void Main(string[] args)
{
TemplateDel<char[]> l_dWriteLeters = new TemplateDel<char[]>(fWriteLetters);
TemplateDel<void> l_dNoArg = new TemplateDel<void>(fWriteLetters);
}
}
the last line of code doesn't compile...
No it is not possible.void is only valid in return types.You can't use it as a type in other contexts. (except the unsafe context)
You need add another overload for your delegate.
public delegate void TemplateDel();
Or simply use an Action.
As Selman22 notes in the other answer:
No it is not possible.
But there is another way, use a lambda to throw away the argument:
TemplateDel<bool> l_dNoArg = new TemplateDel<bool>(_ => fWriteLetters);
(Using _ as the identifier here matches F#'s wildcard – ignore this argument – syntax.)
While not helpful here, this kind of wrapper is helpful when arguments are not interested in are passed and saves writing an extra member just to ignore or re-arrange arguments.
I am standing for a "little" syntax problem and cannt figure out how to correctly write what I desire.
I have the following method:
public void DoSomeMagic(string foo, ref string bar)
{
//DoSomeMagic...
}
Now I would like to offload this code inside a Task.Run I would normally write the following:
public async void Button_Click(object sender, EventArgs args)
{
string foo = "Hello Foo";
string bar = "Hello Bar";
await Task.Run(() => DoSomeMagic(foo, ref bar));
}
This doesn't compile telling me: "Cannot use 'ref' or 'out' parameter 'bar' inside an anonymous method body"
So I thought why even do the () => since I am just calling the method and I could reduce it to this:
Task.Run(DoSomeMagic(foo, ref bar));
This again doesn't compile telling me: Cannot resolve method 'Run(void)', candidates are: Run(Action) and Run(Func)
So again no problem Visual Studio your demand is my command.
And changed the code to this:
Task.Run((Action)DoSomeMagic(foo, ref bar));
Again doesn't compile telling me: Cannot cast expression of type 'void' to type 'Action',
Okay this starts getting tricky...
I than tried to instead of returning void I will just try int and cast to Func
giving me the error: Cannot cast expression of type 'int' to type 'Func'
Saw that one coming but I thought lets give it a try:
So I tried the following approach:
public Action CallDoSomeMagic(string foo, ref string bar)
{
//DoSomeMagic...
return new Action(() => DoSomeMagic(foo, ref bar));
}
Task.Run(CallDoSomeMagic);
But this again gives me the message "Cannot use 'ref' or 'out' parameter 'bar' inside an anonymous method body"
Since my headache is increasing with every try, I thought you guys can help me out.
Is it even possible?
As the message says: you can't do that.
You could take a copy of the parameter value, and capture that, for example:
public Action CallDoSomeMagic(string foo, ref string bar)
{
var snapshot = bar;
return new Action(() => DoSomeMagic(foo, ref snapshot));
}
But note that updates to snapshot are not visible outside the caller via bar.
The reasons for this are two-fold:
Firstly, captured variables used on a lambda become fields on a compiler-generated context class. This works fine for non-ref/out parameters, as they already have a copy semantic. So in the case of my snapshot example, this is actually:
var ctx = new CompilerGeneratedContextClassWithHorribleName();
ctx.foo = foo;
ctx.snapshot = bar;
return new Action(ctx.CompilerGeneratedMethod);
where CompilerGeneratedMethod is:
DoSomeMagic(foo, ref snapshot);
this isn't possible for refs, as you'd essentially need the field to be a reference to a string-reference, which is... messy.
But more importantly: consider the lifetime of the caller. This could be:
void SomeMethod() {
string s = "abc";
CallDoSomeMagic("def", ref s);
}
Note in particular that the code needs to work even if the delegate is invoked much later - as indeed we might expect it to in your case since it involves Task and async. Now: if SomeMethod has exited: where is that reference to a string-reference pointing? Hint: it is just an arbitrary location on the stack, now out of scope.
Just to give a simpler workaround: instead of passing ref string bar, consider passing SomeType obj, where obj.Bar is the string you want; i.e.
public Action CallDoSomeMagic(string foo, SomeType obj)
{
return new Action(() => DoSomeMagic(foo, obj));
}
public void DoSomeMagic(string foo, SomeType obj)
{
// read and write obj.Bar here
}
Note you could also move foo to obj.Foo if you wanted.
ok, so in javascript, we can declare an object like this,
var obj={name:"Irshu",age:22};
console.log(obj);
How do we do the same in c#? the reason i ask because my function need to return a string and a bool together. I dont want to create a class for it, and i dont want to use the dictionary. Are there any alternatives?
public void Message(){
var obj=GetObject(val);
Messagebox.Show(Convert.ToString(obj.ind));
}
public object GetObject(string val){
return new {ind=val,flag=true};
}
This is not valid, is it?
.Net supports ExpandoObject since .NET 4.
http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject%28v=vs.110%29.aspx
It lets you declare the object and add properties as your would in javascript.
Traditionally it is for JS interop and I can't recommend it for production work. Tuple<T> is more appropriate as you get strong typing for free. Ultimately you will write less code and see less runtime errors.
What you have in your code is an anonymous type. Anonymous types cannot exist outside the scope in which they are declared. Generally, we use these for transforming LINQ results to temporary objects.
You can't return anonymous types from a method. You can do however something like this:
public void Message(){
var obj = new { ind = "oaiwejf", flag = true };
Messagebox.Show(obj.ind);
}
EDIT
Check this MSDN article
turns out, its posible, one genius on the internet posted this:
public void Message()
{
var obj=GetObject("Irshu");
var y= Cast(obj, new { ind= "", flag= true });
Messagebox.Show(y.ind); //alerts Irshu
}
public object GetObject(string val){
return new {ind=val,flag=true};
}
T Cast<T>(object obj, T type)
{
return (T)obj;
}
Say I have a method:
public void SomeMethod(String p1, String p2, int p3)
{
#if DEBUG
object[] args = GetArguments();
LogParamaters(args);
#endif
// Do Normal stuff in the method
}
Is there a way to retrieve an array of the arguments passed into the method, so that they can be logged?
I have a large number of methods and want to avoid manually passing the arguments by name to the logger, as human error will inevitably creep in.
I'm guessing it will involve reflection in some form - which is fine, as it will only be used for debugging purposes.
Update
A little more information:
I can't change the method signature of SomeMethod, as it is exposed as a WebMethod and has to replicate the legacy system it is impersonating.
The legacy system already logs the arguments that are passed in. To start with the new implementation will wrap the legacy system, so I'm looking to log the parameters coming into the C# version, so that I can verify the right parameters are passed in in the right order.
I'm just looking to log the argument values and order, not their names.
If you use Postsharp you can simply add an attribute to the method you want to log. Within this attribute you can write the logging code and also will provide the arguments you need. This is known as cross cutting concerns and AOP (Aspect orientated programming)
I am unsure if the API to access the call stack provides a means to get the argument list.
However there are ways to inject IL to intercept method calls and execute custom code.
The Library I use frequently is PostSharp by Gael Fraiteur, it includes an application that runs postbuild and injects IL in your output assemblies depending on the Aspects that you are using. There are attributes with which you can decorate assemblies, types, or individual methods. For instance:
[Serializable]
public sealed class LoggingAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs eventArgs)
{
Console.WriteLine("Entering {0} {1} {2}",
eventArgs.Method.ReflectedType.Name,
eventArgs.Method,
string.Join(", ", eventArgs.Arguments.ToArray()));
eventArgs.MethodExecutionTag = DateTime.Now.Ticks;
}
public override void OnExit(MethodExecutionArgs eventArgs)
{
long elapsedTicks = DateTime.Now.Ticks - (long) eventArgs.MethodExecutionTag;
TimeSpan ts = TimeSpan.FromTicks(elapsedTicks);
Console.WriteLine("Leaving {0} {1} after {2}ms",
eventArgs.Method.ReflectedType.Name,
eventArgs.Method,
ts.TotalMilliseconds);
}
}
After this you can just decorate the method you want with this Attribute:
[Logging]
public void SomeMethod(String p1, String p2, int p3)
{
//..
}
Well, if you just want to pass the values, you can cheat and define an object array:
public static void LogParameters(params object[] vals)
{
}
This will incur boxing on value types and also not give you any parameter names, however.
Say I have a method:
public void SomeMethod(String p1, String p2, int p3)
{
#if DEBUG
LogParamaters(p1, p2, p3);
#endif
// Do Normal stuff in the method
}
Update: unfortunately reflection will not do it all automatically for you. You will need to provide the values, but you can use reflection to provide the param names/types:
How can you get the names of method parameters?
So the method sig would change to something like:
public static void LogParameters(string[] methodNames, params object[] vals)
{ }
Then you can enforce/assume that each index in each collection tallies, such that methodNames[0] has the value vals[0].
Well params help with the log call, but won't help the existing method signatures. Logging using an AOP framework might be a more productive approach?
Sure can ...check out this post, it gets the actual values of the params.
how to enumerate passed method parameters
There's some functionality with the dynamic type system that can do it, but then your class needs to inherit from the dynamic base classes
might not work in some scenarios but should get you started :)
class Program
{
static void Main(string[] args)
{
M1("test");
M2("test", "test2");
M3("test", "test2", 1);
Console.ReadKey();
}
static void M1(string p1)
{
Log(MethodBase.GetCurrentMethod());
}
static void M2(string p1, string p2)
{
Log(MethodBase.GetCurrentMethod());
}
static void M3(string p1, string p2, int p3)
{
Log(MethodBase.GetCurrentMethod());
}
static void Log(MethodBase method)
{
Console.WriteLine("Method: {0}", method.Name);
foreach (ParameterInfo param in method.GetParameters())
{
Console.WriteLine("ParameterName: {0}, ParameterType: {1}", param.Name, param.ParameterType.Name);
}
}
}
As long as you know what types to expect you could log them in an SQL database. Write a method that does a type check, and then fills the appropriate DB column with the parameter (argument) value. If you have a custom type then you can use the type name and save that as string in it's own special column.
-Edit
Also, using the MethodBase.Name extension method, you could associate your parameters with the method that took them as arguments as mentioned in another post below. Be a handy way of keeping track of all methods used, and with which arguments, and of which type.
Is this even vaguely a good idea? :)
Here's what I came up with as a solution:
PostSharp or another AOP solution wasn't really practical in this situation, so unfortunately I had to abandon that idea.
It appears that while it is possible to parameter names and types using reflection, the only way to access the runtime values is with a debugger attached.
See here for more info:
StackOverflow
microsoft.public.dotnet.framework
So that still left me with the problem of ~50 methods that needed this logging adding by hand.
Reflection to the rescue...
public String GetMethodParameterArray()
{
var output = new StringBuilder();
output.AppendLine();
Type t = typeof(API);
foreach (var mi in t.GetMethods())
{
var argsLine = new StringBuilder();
bool isFirst = true;
argsLine.Append("object[] args = {");
var args = mi.GetParameters();
foreach (var pi in args)
{
if (isFirst)
{
isFirst = false;
}
else
{
argsLine.Append(", ");
}
argsLine.AppendFormat("{0}", pi.Name);
}
argsLine.AppendLine("};"); //close object[] initialiser
output.AppendLine(argsLine.ToString());
output.AppendFormat("Log(\"{0}\",args);", mi.Name);
output.AppendLine();
output.AppendLine();
}
return output.ToString();
}
This code snippet loops through the methods on a class and outputs an object[] array initialised with the arguments passed into the method and a Log call containing the arguments and the method name.
Example output:
object[] args = {username, password, name, startDate, endDate, cost};
Log("GetAwesomeData",args);
This block can then be pasted into the top of the method to achieve the required effect.
It is more manual than I would have liked, but it is a lot better than having to type the parameters by hand and far less error prone.