I want to make a function that will return the sum ( concatenation for string ) of any number of argument I pass.
Below function works well with string but throwing error for other data types ( int, double...etc)
What am I missing?
Error:
Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:
The call is ambiguous between the following methods or properties:
'System.Console.WriteLine(string, params object[])' and
'System.Console.WriteLine(char[])'
at CallSite.Target(Closure , CallSite , Type , Object )
Code:
public static dynamic sumfunction(params dynamic[] arr)
{
dynamic res=null;
for(int i=0;i<arr.Length;i++)
{
res += arr[i];
}
return res;
}
static void Main(string[] args)
{
dynamic vv=sumfunction("my","name");
Console.WriteLine(vv);
vv = sumfunction(5,6,7);
Console.WriteLine(vv);
}
Your current code is throwing an exception in Console.WriteLine(vv); because vv is null, and the call becomes ambiguous in the same way that this code does:
// error CS0121: The call is ambiguous between the following methods or properties:
// 'Console.WriteLine(char[])' and 'Console.WriteLine(string)'
Console.WriteLine(null);
So why is vv null in the second case? Because you started with null, and added to it. I suspect the binder is converting both null and the non-null integer to int? and then performing addition using the lifted addition operator. That reasoning is only an educated guess, but certainly the result is null. (You can check that with normal null checks on the result.)
The fix is to start with "the first element in the array" for the addition rather than with null, and only return null if the input array is either null or empty (or if a real addition ends up with null - which it could do if null is one of the elements in the array). You can also fix Console.WriteLine causing a problem even in that case by using object as the type of the local variable receiving the result, rather than dynamic. Here's an example with all that fixed, as well as using more idiomatic names:
using System;
using System.Linq;
public class Program
{
public static dynamic Sum(params dynamic[] arr)
{
if (arr == null || arr.Length == 0)
{
return null;
}
dynamic result = arr[0];
foreach (var item in arr.Skip(1))
{
result += item;
}
return result;
}
static void Main(string[] args)
{
object sum = Sum("my", "name");
Console.WriteLine(sum);
sum = Sum(5, 6, 7);
Console.WriteLine(sum);
Console.WriteLine(null);
}
}
Output:
myname
18
Related
I'm trying to take objects out of an object list to an int list. If the object list's value contains a string than I want to convert it to an int. the error that I'm getting is "cannot convert from 'object' to 'System.ReadOnlySpan'. I've tried looking up examples and information about lists made of objects but couldn't find anything.
I'm also at a loss as to what to do with the 'else' part of the code.
public class ListFilterer
{
public static IEnumerable(int) GetIntegersFromList(List(object) listOfItems)
{
List<int> Integers = new List<int>();
foreach (var value in listOfItems)
{
int number = 0;
bool success = Int32.TryParse(value, out number);
if (success)
{
Integers.Add(number);
}
else
{
Integers.Add(number);
}
}
return Integers;
}
}
It'll probably work out if you TryParse value.ToString() instead, if you're looking for anything that might look like an int and can be converted to an int. If you only want things that actually are ints, something like if(value is int number) should work if your c# version is recent. If it's older you may have to if(value is int) and then cast the value inside the if
Your code can be simplified to:
foreach(...){
int.TryParse(value.ToString(), out var n);
integers.Add(n);
}
Or
foreach(...){
if(value is int)
integers.Add((int)value);
else
integers.Add(0);
}
You could simply use:
var ints = listOfItems
.Select(o => { int.TryParse(o.ToString(), out int num); return num;} )
.ToList();
This will work as you wish, as if conversion fails num is 0 by default.
If Try Parse fails number is automatically 0 so you can directly write this
Int32.TryParse(value, out int number)
Integers.Add(number);
Maybe you can find the better way
var intList = objs.ConvertAll(delegate (object obj) { return (int)obj; });
Why does this program show an error for using seq:
class Program
{
delegate double Sequence(int r);
void F(ref Sequence seq) // Here
{
Sequence seq2 = r =>
{
if (r % 2 == 0)
return seq(r); // Here
else
return seq(2 * r); // Here
};
seq = seq2;
}
static void Main()
{
}
}
Error CS1628 Cannot use ref, out, or in parameter 'seq' inside an
anonymous method, lambda expression, query expression, or local
function CsharpRefLambdaTest
The problem is with that the parameter seq is a reference type. But why is it wrong? what't the problem with a reference seq? If seq is not reference the program has no errors.
Is there any way to correct the program while keeping seq as a reference?
The program is just an test and it is not going to do anything.
================
I need to use the value of seq to define a new Sequence seq2 and then assign seq = seq2. But the values of seq are not usable. If the values of seq are not going to be usable why does C# allow seq to be a reference at all?
===============================
Edit:
The program above is just simplified version of the following:
class Program
{
delegate double Sequence(int r);
Sequence G(Sequence seq)
{
Sequence seq2 = r =>
{
if (r % 2 == 0)
return seq(r);
else
return seq(2 * r);
};
return seq2;
}
void F(ref Sequence seq)
{
seq = G(seq);
}
static void Main()
{
}
}
But I don't understand why I cannot remove G and instead add the defining code of G insideF`.
the error message here is: "CS1628 Cannot use ref, out, or in parameter 'seq' inside an anonymous method, lambda expression, query expression, or local function" - seq2 is the lambda expression; it has nothing to do with reference types, but rather: lifetimes. You could, after all, call it like:
void Foo() {
Sequence bar = SomeMethod; // bar is a LOCAL of Foo
F(ref bar);
// not shown: perhaps do something with bar, perhaps not
}
at which point, F would need to somehow create a lambda that contains within it a reference to a position on the stack (a reference to the local bar). Now note that this lambda, being an object, could outlive Foo, and bar would be an undefined - and possibly reused - memory location.
So: you can't "capture" parameters that are passed as ref, in our out, where I'm using "capture" loosely here to mean "use within the scope of a lambda or anonymous method that forms an expression-tree, delegate expression; or within an iterator block or async continuation".
Just remove the ref. You don't need it, and it isn't helping. If your intention is to change the delegate, then consider instead returning the composed delegate.
as an alternative workaround: snapshot the value and capture the snapshot:
void F(ref Sequence seq)
{
var tmp = seq;
seq = r =>
{
if (r % 2 == 0)
return tmp(r);
else
return tmp(2 * r);
};
}
this avoids the problematic scenario because the snapshot dereferences the ref parameter, meaning: there is now no possibility that we're capturing a stack location.
It seems that if there is only one parameter of type array on a method
the value of the parameter passed to my LogException() method is not an array anymore.
When there is more than one parameter on a method, or if the one parameter is not an array, it works as expected. But when I try to pass an array, it seems that the first value of the array becomes the parameter that was passed.
All comments are inlined to explain and show the problem. The problem first appears at "point 4"; once the wrong value is found, the parameter information being stored in my exception is wrong. The other points clarify the subsequent confusion that arises. I have no idea how solve it.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Testapp
{
class Program
{
static void Main(string[] args)
{
string[] tmp1 = new string[2];
tmp1[0] = "val1";
tmp1[1] = "val2";
//please look at point 1
TestMethod1(tmp1);
//please look at point 2
TestMethod2(tmp1, "just a value");
}
private static void TestMethod1(string[] ArrayType)
{
try
{
throw new System.Exception("blow");
}
catch (System.Exception ex)
{
LogException(ex, ArrayType);
foreach (System.Collections.DictionaryEntry entry in ex.Data)
{
string tmp1 = entry.Key.ToString();
string tmp2 = entry.Value.ToString();
//point 1 (for param:ArrayType... well there is only 1 parameter)
//the value of tmp2 = val1
//and should be {val1,val2}
System.Diagnostics.Debugger.Break();
}
}
}
private static void TestMethod2(string[] ArrayType, string StringType)
{
try
{
throw new System.Exception("blow");
}
catch (System.Exception ex)
{
LogException(ex, ArrayType, StringType);
foreach (System.Collections.DictionaryEntry entry in ex.Data)
{
string tmp1 = entry.Key.ToString();
string tmp2 = entry.Value.ToString();
//point 2 (for param:ArrayType)
//the value of tmp2 = {val1,val2} (correct, this what i expected)
//please look at point 3
System.Diagnostics.Debugger.Break();
}
}
}
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
public static void LogException(System.Exception Exception, params object[] args)
{
using (CallerInfo callerinfo = new CallerInfo(1))
{
callerinfo.AddParameterInfo(Exception, args);
}
}
private class CallerInfo : IDisposable
{
private System.Reflection.ParameterInfo[] parameterinfos = null;
private string identifiername = string.Empty;
private string assemblyname = string.Empty;
public void AddParameterInfo(System.Exception Exception, params object[] sourceargs)
{
if (parameterinfos == null) return;
string locationname = identifiername + " - param:";
foreach (System.Reflection.ParameterInfo ParameterInfo in parameterinfos)
{
string KeyName = locationname + ParameterInfo.Name;
object parameter = null;
try
{
System.Diagnostics.Debugger.Break();
//point 4
//the next line goes wrong when there is ONLY 1 parameter on a method of type array
parameter = sourceargs[ParameterInfo.Position];
}
catch
{
parameter = null;
}
if (parameter == null)
{
if (!Exception.Data.Contains(KeyName))
{
Exception.Data.Add(KeyName, "*NULL*");
}
}
else
{
if (ParameterInfo.ParameterType.IsArray)
{
//point 3
//this is where i got confused
//the check if (ParameterInfo.ParameterType.IsArray) is returning true.. correct the first parameter in both methods are of type array
//however for TestMethod1 (that is having ONLY 1 parameter) the value of parameter (see point 4) is NOT an array anymore?????
//for TestMethod2 (that is having 2 parameters, but the SAME first parameter as passed in TestMethod1) the value of parameter (see point 4) is an array what is correct
System.Diagnostics.Debugger.Break();
if (parameter.GetType().IsArray)
{
string arrayvaluelist = "{";
try
{
System.Collections.ArrayList arraylist = new System.Collections.ArrayList((System.Collections.ICollection)parameter);
foreach (object arrayitem in arraylist)
{
if (arrayitem == null) { arrayvaluelist = arrayvaluelist + "*NULL*,"; continue; }
arrayvaluelist = arrayvaluelist + arrayitem.ToString() + ",";
}
arrayvaluelist = arrayvaluelist.Substring(0, arrayvaluelist.Length - 1);
arrayvaluelist = arrayvaluelist + "}";
}
catch
{
arrayvaluelist = "Error in constructing the arrayvalue list for parameter: " + ParameterInfo.Name;
}
if (!Exception.Data.Contains(KeyName))
{
Exception.Data.Add(KeyName, arrayvaluelist);
}
}
else
{
//point 5 -- i shouldn't be here !!!!
System.Diagnostics.Debugger.Break();
if (!Exception.Data.Contains(KeyName))
{
Exception.Data.Add(KeyName, parameter.ToString() + " warning wrong value is returned.");
}
}
}
else
{
if (!Exception.Data.Contains(KeyName))
{
Exception.Data.Add(KeyName, parameter.ToString());
}
}
}
}
}
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
public CallerInfo(int Level)
{
try
{
System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace();
System.Reflection.MethodBase methodbase = stackTrace.GetFrame(Level + 1).GetMethod();
parameterinfos = methodbase.GetParameters();
assemblyname = methodbase.ReflectedType.Assembly.ManifestModule.Name;
identifiername = methodbase.ReflectedType.FullName + "." + methodbase.Name;
}
catch
{
//broken
}
}
void IDisposable.Dispose()
{
parameterinfos = null;
}
}
}
}
Thank you very much for the good Minimal, Complete, and Verifiable code example. While the question as originally worded was not especially clear, having a good MCVE ensured that the exact issue can easily be understood. (It's unfortunate that three different people didn't bother to look at the most important part of the question…it seems the worst questions get up-voted, even while a not-entirely-clear question but which includes full code — the very most important part of any question — gets down-voted :( ).
Anyway, the issue here is your use of params in conjunction with the fact that the parameter itself is an array. It's important to understand what params actually means: the parameter declared in that way is in fact an array, and follows all the normal rules for regular array parameters. The only thing that params gives you is that you may optionally populate the array by providing multiple argument values, and the compiler will take those values and combine them into an array.
Where you got into trouble is that if you provide an array as the argument value, the compiler treats that as the actual array argument that was declared for the method and does not do any additional work.
The issue might have been more obvious if you'd been passing an object[] instead of a string[]. In that case, you can easily see that the whole object[] array matches exactly the parameter type for the LogException() method, and so is passed directly rather than being stored in another object[]. As it happens, arrays in C# are "covariant". In this case, the main thing that means is that if a method is expecting an object[] array, you can pass it an array of any type, because the elements of the passed array inherit the object type.
So when you pass the ArrayType value, the C# compiler recognizes this as compatible with the LogException() method's object[] parameter type, and just passes the array itself as that parameter, rather than storing it as a single element in an object[]. Then later when you go to retrieve the parameter values, it seems as though your LogException() method had been called by a method with two different parameters, i.e. two string values of "val1" and "val2", respectively.
So, how to fix this? Very easy: you just have to hide the array nature of the value from the C# compiler for the purpose of the call:
LogException(ex, (object)ArrayType);
I.e. in your TestMethod1() method, cast the ArrayType value to object when calling LogException(). This will force the compiler to treat the array object as a simple object value, preventing it from matching the value's type to the params object[] args parameter type, and store the value in a new object[] array for the call as you'd expected.
This question already has answers here:
How does C# choose with ambiguity and params
(3 answers)
Closed 8 years ago.
How does c# make params work.
When you have code like
static string Concat(int arg)
{
return arg.ToString();
}
static string Concat(int arg, params string[] p)
{
string result = string.Empty;
result = result + arg.ToString();
foreach (var s in p)
{
result = result + s;
}
return result;
}
Resharper says the method with params hides the other method. Does this imply that under the hood The other method is being defined and calling the one with params passing in an empty array? Or something else entirely?
(please don't get bogged down on the crappy code - its just an example)
Edit to explain:
If i do not define the static string Concat(int arg) method i can still call the second as
var s = Concat(123);
despite that method not being defined .... so the question is: is the first method defined implicitly under the hood and calling the second with an empty array. Note i changed the arg type from string to int.
to explain the weirdness as i see it. When you call as above ... it hits the params object with an empty array, the param is not null - which is what i expected. When i first wrote that foreach loop i had a null check on params then discovered i didn't need it.
So ... you reason that it must be wrapping any params after the first parameter in an array right? A little bit of inlined code? ... so if you passed in "dave" you would get freddave as the output ....
However pass null into it ....
static void Main(string[] args)
{
Console.WriteLine(Concat("fred",null));
}
//static string Concat(string arg)
//{
// return arg;
//}
static string Concat(string arg, params int[] p)
{
string result = string.Empty;
result = result + arg;
if (p != null)
{
foreach (var s in p)
{
result = result + s.ToString();
}
}
return result;
}
and you discover in this case p is actually null ...
If you do that with the string example ... id of expected an array with 1 element of null ... instead the entire params object is null.
I think calling it "hiding" is misleading here, to be honest.
Both methods are definitely created, but if you call:
Concat(5);
then for that invocation both methods are applicable (in the terminology of the C# spec section 7.5.3.1) but the first method is better (section 7.5.3.2) because of this:
Otherwise, if MP is applicable in its normal form and MQ has a params array and is applicable only in its expanded form, then MP is better than MQ.
So in that case, the first method would be called.
The second method cannot be called using params expansion without specifying at least one string. It can still be called with an empty array, of course:
Concat(5, new string[0]);
I'm playing around with a very simple program to take an array of doubles and return the standard deviation. This part worked but I wanted to make the code more reusable. I would like to make it so the method can accept a parameter of any type that could be considered numeric and return the standard deviation instead of hardcoding a double type (like I initially did in this program). How does one go about this and what is the proper term for it?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication5
{
class Program
{
static void Main(string[] args)
{
double[] avg = { 3.4, 55.6, 10.0, 4.5, 2, 2 };
double x = avg.Average();
//first round of testing
Console.WriteLine("The average of the first array is below ");
Console.WriteLine(x);
Console.WriteLine("below should be the standard deviation!");
Console.WriteLine(CalculateStandardDeviation(avg));
Console.ReadLine();
int[] intAvg = { 4, 3, 5, 6, 2 };
double secondAvg = intAvg.Average();
Console.WriteLine("The average of the second array is below ");
Console.WriteLine(secondAvg);
//this is where the error is happening
//CalculateStandardDeviation(secondAvg);
}
//this is where I tried to make the query more reusable
public static double CalculateStandardDeviation(IEnumerable<double> values)
{
double avg = values.Average();
double sum = 0;
foreach (double d in values)
{
sum += Math.Pow((d - avg), 2);
}
return Math.Pow(sum / (values.Count() - 1),.5);
}
}
}
You could use something like this:
public static decimal CalculateStandardDeviation<T>(IEnumerable<T> values)
{
IEnumerable<decimal> decimalValues = values.Select(v => Convert.ToDecimal(v));
decimal result = 0;
// calculate standard deviation on decimalValues
return result;
}
It will throw an exception if values contains values that can't be converted to a decimal, but will work if the values are of an appropriate type, and I think that makes perfect sense.
Unfortunately, there is no base class for all numbers. You can do this with a generic run-time checking method, or a compile-time safe set of overloads.
Generic Method:
public static T CalculateStandardDeviation(IEnumerable<T> values)
{
var valueArray = values.Select(Convert.ToDecimal).ToArray();
//...
return (T)standardDeviation;
}
The problem with using a single generic method is that you can't put a type constraint on the type parameter that would restrict it to only numeric types. You would have to resort to failing at run-time. There would be nothing to stop you from calling the method with an array of strings, or objects, or Colors, or HttpWebRequests, etc. and unless you do in fact know how to calculate the standard deviation of a color, you should probably stick to individual overrides for a particular numeric type:
I would recommend using the decimal type as your main implementation, and then casting everything to it.
Type-Specific Overloads:
public static decimal CalculateStandardDeviation(IEnumerable<decimal> values)
{
//...
}
public static double CalculateStandardDeviation(IEnumerable<double> values)
{
return (double)CalculateStandardDeviation(values.Select(Convert.ToDecimal));
}
public static int CalculateStandardDeviation(IEnumerable<int> values)
{
return (int)CalculateStandardDeviation(values.Select(Convert.ToDecimal));
}
// etc...
Use C# Generics.
Your function signature will be:
public static T CalculateStandardDeviation(IEnumerable<T> values)
And you can use it like:
int stdDev = CalculateStandardDeviation([int-array]);
double stdDev = CalculateStandardDeviation([double-array]);
Please follow this link:
http://msdn.microsoft.com/en-us/library/ms379564%28VS.80%29.aspx
Edit:
To resolve the Average issue on the generic types, please take a look in this library:
How to Implement Generic Method to do Math calculations on different value types
Obs: Suggestion from Brian.
EDIT
You should use JLRishe's answer, it's much more elegant than this.
You should probably start by adding generics to your method and use the type converter to transform your unknown input into doubles like so :
public static double CalculateStandardDeviation<TSource>(IEnumerable<TSource> inputs)
{
var converter = TypeDescriptor.GetConverter(typeof (double));
if (!converter.CanConvertFrom(typeof(TSource)))
return 0;
var values = new List<double>();
foreach (var value in inputs)
{
values.Add((double) converter.ConvertFrom(value));
}
// Your logic here ...
return ...;
}
I did not tested this snippet but you get the idea.
Foreword:
this answer builds on
How to verify whether a type overloads/supports a certain operator?
and
http://www.codeproject.com/Articles/87438/TinyLisp-A-Language-and-Parser-to-See-LINQ-Express
The second link shows how to compile and evaluate linq expressions.
In short you could forego static type safety and check for the ability of a type to support specific operations at runtime (first link), in case it does not you could throw an exception as the following sample demonstrates:
void Main()
{
DoAdd<float>(5,6);
DoAdd<int>(5,6);
DoAdd<bool>(true,false);
}
// Define other methods and classes here
static void DoAdd<T>(T in1, T in2){
if(!HasAdd<T>()){throw new Exception("Unsupported Type!");}
var c1 = Expression.Constant(in1, typeof(T));
var c2 = Expression.Constant(in2, typeof(T));
var expression=Expression.Add(c1, c2);
Expression<Func<T>> lExpression = Expression.Lambda<Func<T>>(expression);
Func<T> fExpression = lExpression.Compile();
Console.WriteLine(fExpression());
}
static bool HasAdd<T>() {
var c = Expression.Constant(default(T), typeof(T));
try {
Expression.Add(c, c); // Throws an exception if + is not defined
return true;
} catch {
return false;
}
}
Passing an IEnumerable of Numeric Values as a parameter to method will be supported in C# 6.0