Getting the ambiguous call as arrangement of parameters are different: short,int / int,short /byte,int / int,byte
As Function signature is:
1.Number of arguments/parameters
2.Type of arguments/parameters
3.Arrangement of arguments/parameters
Why the call is ambiguous ? should it belongs to the similar type ?...
code:
class Program
{
static void Main(string[] args)
{
test abbb = new test();
//abbb.add(2.2f,1);
// abbb.add(2,2.2f);
abbb.add(255,1);
abbb.add(1,256);
Console.ReadLine();
}
}
class test
{
public int add(byte i , int f) {
return i + f;
}
public int add(int i, byte f)
{
return i + f;
}
public int add(short i, int f)
{
return i + f;
}
public int add(int i, short f)
{
return i + f;
}
}
By default, any 'Magic Number' will be treated as an Integer, but sometimes for ease of use the compiler can convert to another number format implicitly if it has enough information to do so.
In order to get around the ambiguous calls, you would be best explicitly defining typed variables for the numbers first, then passing them into the functions to remove any ambiguity.
class Program
{
static void Main(string[] args)
{
test abbb = new test();
Console.WriteLine(abbb.add(32767, 32770)); //short , int
Console.WriteLine(abbb.add(32770, 32767)); //int ,short
Console.WriteLine(abbb.add(255, 32770)); // byte,int
Console.WriteLine(abbb.add(32770, 255)); // int,byte
Console.ReadLine();
}
}
class test
{
public int add(byte f, int i)
{
return i + f;
}
public int add(int i, byte f)
{
return i + f;
}
public int add(short i, int f)
{
return i + f;
}
public int add(int f, short i)
{
return i + f;
}
}
No ambiguity due to mentioned specific range of types...
It is ambiguous because C# does not know which of the two numbers is which of the types.
Both 1 and 256 may a be a short and both may be an int.
You may use explicit casting to "choose" one of the methods.
Related
I started programming recently and I have troubles. I was wondering how to use int, double and string with delegates. Every time I mix them I get error CS0407. I have some samples but they only use int inside delegates. Thanks in advance.
using System;
namespace _8pirmas
{
class Program
{
public delegate string IsvedimoEiliskumas(string v, string p, string s, int am, int pat);
static string vardas(string a, string b, string c, int d, int e) { return a; }
static string pavarde(string a, string b, string c,int d, int e) { return b; }
static string specialybe(string a, string b, string c,int d, int e) { return c; }
static int amzius(string a, string b, string c, int d, int e) { return d; }
static int patirtis(string a, string b, string c, int d, int e) { return e; }
static void Main(string[] args)
{
IsvedimoEiliskumas[] funkcija = new IsvedimoEiliskumas[3];
string v, p, s;
int am, pat;
int pasirinkimas = 1;
Console.WriteLine($"Įveskite darbuotojo informaciją.");
v = Console.ReadLine();
p = Console.ReadLine();
s = Console.ReadLine();
Console.WriteLine("Įveskite amžių: ");
am = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Įveskite stažą: ");
pat = Convert.ToInt32(Console.ReadLine());
Console.WriteLine($"Kaip norėtumėte išdėstyti šią informaciją?");
for (int i = 0; i < 3; i++)
{
Console.WriteLine($"{i + 1} zingsnis: (1)Vardas, (2)Pavarde, (3)Specialybe,
(4)Amzius, (5)Patirtis, (6)Atlyginimas");
pasirinkimas = Convert.ToInt32(Console.ReadLine());
switch(pasirinkimas)
{
case 1: funkcija[i] = vardas; break;
case 2: funkcija[i] = pavarde; break;
case 3: funkcija[i] = specialybe; break;
case 4: funkcija[i] = amzius; break;
case 5: funkcija[i] = patirtis; break;
}
}
for (int i = 0; i< 3; i++)
Console.WriteLine($"Atsakymas {i + 1} veiksmo { funkcija[i](v, p, s, am , pat)}");
Console.ReadKey();
}
}
}
Let's have a look at specialybe and amzius methods.
static string specialybe(string a, string b, string c,int d, int e) ...
static int amzius(string a, string b, string c, int d, int e) ...
These methods have different signatures (one returns string the other int) so you cannot mix and match them.
Since you're using the response only as text a good hack would be to .ToString() d & e which would allow keeping the signatures of all methods the same.
static string specialybe(string a, string b, string c,int d, int e) { return c; }
static string amzius(string a, string b, string c, int d, int e) { return d.ToString(); }
static string patirtis(string a, string b, string c, int d, int e) { return e.ToString(); }
delegates are like method interfaces: you have to match their exact signature, including the return type. Since the return type of delegate IsvedimoEiliskumas is string, any method that fulfills the delegate must also have return type string (as well as all the same method parameter types, in order).
From your code amzius and patirtis have a different return type (int) than IsvedimoEiliskumas. To resolve this issue, you have two options:
1. Change the fulfilling method signatures' return type
Change amzius and patirtis so that they return a string. The simplest implementation would look like this:
static string amzius(string a, string b, string c, int d, int e) { return d.ToString(); }
static string patirtis(string a, string b, string c, int d, int e) { return e.ToString(); }
2. Make your delegate generic
To support multiple return types in your delegate, make it generic:
public delegate T IsvedimoEiliskumas<T>(string v, string p, string s, int am, int pat);
You can now return whatever you want from a method or lambda fulfilling IsvedimoEiliskumas. The downside is, in your example, you have to specify a concrete type in your declaration of funkcija and you will still need to change your fulfilling methods to match its signature:
// Still errors on amzius and patirtis, and you have same issue
IsvedimoEiliskumas<string>[] funkcija = new IsvedimoEiliskumas<string>[3];
// Now errors on vardas, pavarde, and specialybe instead
IsvedimoEiliskumas<int>[] funkcija = new IsvedimoEiliskumas<int>[3];
// Errors on everything, but we are more abstract than string or int
IsvedimoEiliskumas<object>[] funkcija = new IsvedimoEiliskumas<object>[3];
To make this work, you would need to change every method used in funkcija to have return type object. You could then cast it to the original type when needed.
Side note: in situations where you only use a method to fulfill a delegate, you can construct an instance of the delegate directly as a lambda:
static IsvedimoEiliskumas vardas = (a, b, c, d, e) => a;
Your delegate have a return type of a string, and in your last two methods you put the return type as int
If you dont have the Visual Studio already, please install, is worth it. There you have the error on the IDE (i.e Visual Studio).
public int Add2(int a, int b) => a + b;
public int Add3(int a, int b, int c) => a + b + c;
public int Add4 (int a,int b,int c,int d) => a + b + c + d;
How can we write these methods under a single method?
Use params int[] in your Add method and you can add as many numbers as you'd like.
Something like:
using System;
public class Program
{
public static void Main()
{
Console.WriteLine(Add(1, 2, 3, 4, 5));
}
public static int Add(params int[] numbers)
{
int sum = 0;
foreach (int n in numbers)
{
sum += n;
}
return sum;
}
}
Result:
15
Fiddle Demo
Enhancement
With Linq, the code get's shorter
using System;
using System.Linq;
public class Program
{
public static void Main()
{
Console.WriteLine(Add(1, 2, 3, 4, 5));
}
public static int Add(params int[] numbers)
{
return numbers.Sum();
}
}
Result:
15
Fiddle Demo
Try optional arguments.
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#optional-arguments
Write a method A with
Add (int a, int b, int c = 0, int d = 0) { }
Then based on value passed in c and d param do calculation.
The value a and b are always used in three functions. These values are mandatory in your function. The value c and d aren't always used. If you want to combine all of the functions, just make these values optional by giving them default value.
public int Add(int a, int b, int c = 0, int d = 0){
return a + b + c + d;
}
Yet-another-way..fun with Func and (also) Linq :)
static Func<int[], int> Add = ((i) => i.Sum());
public static void Main()
{
Console.WriteLine(Add.Invoke(new[] {1,2,3,4,5}));
Console.WriteLine(Add.Invoke(new[] {8}));
Console.WriteLine(Add.Invoke(new[] {-2, -4, 6}));
}
//15
//8
//0
Here is demonstration of the problem:
class Program
{
static double Func(double a, double b) { return a * 1000 + b * b; }
static void Main(string[] args)
{
var a = 1.1d;
var b = 2.2d;
Console.WriteLine(Func(a, b));
// this is the problem, function doesn't recognize when a and b
// "accidentally" exchanged, target is to make this row a compile-time error
Console.WriteLine(Func(b, a));
}
}
This become an issue if there are methods with many parameters (e.g. ten of double type):
double Func(double parameter1, double parameter2, ..., double parameter10);
Question: is there a way to validate parameters when calling method, so that programmer is less prone to do a mistake?
This is not an issue if parameter types are different. I thought what maybe wrapping into new types will help:
class A
{
private double _value;
public static implicit operator A(double value) { return new A() { _value = value }; }
public static implicit operator double(A value) { return value._value; }
}
class B
{
private double _value;
public static implicit operator B(double value) { return new B() { _value = value }; }
public static implicit operator double(B value) { return value._value; }
}
class Program
{
static double Func(A a, B b) { return a * 1000 + b * b; }
static void Main(string[] args)
{
A a = 1.1d;
B b = 2.2d;
Console.WriteLine(Func(a, b));
Console.WriteLine(Func(b, a)); // compile-time error! yay!
Console.WriteLine(Func(a, b) + 123.123d - a * 2); // implicit conversion power
Console.ReadKey();
}
}
And it does, but I am quite unsure if this method is efficient. I have doubts if this is a good idea at all. Is it? Or is there better one?
I know what I can be absolutely safe if I always call method like this (using named arguments method call)
Func(a:a, b:b);
This shouldn't bring any overhead in code, but a lot of typing. Wrapping is better because it is done once (creating new type is easy), but it probably has overhead.
If two arguments are of the same type, it's not possible to detect at compile-time, run-time or otherwise that the name of the argument variable corresponds to the name of the parameter. This is kind of an open question, but I will offer you a couple ideas.
As Mehrzad suggested, consider grouping parameters by some type. For example, instead of double Distance(double x1, double y1, double x2, double y2), consider double Distance(Point p1, Point p2)
In general, if your method has more than 4-5 parameters, consider refactoring. Maybe your method is trying to do too many things and the logic can be divided?
If what you actually want to do is to perform some check such as ensuring that a < b, consider looking into Code contracts. You could also use Debug.Assert(), but this only works at run-time.
I wouldn't recommend the kind of implicit conversion you propose. For me, it feels hacky and unintuitive that A a = 1.1 should have no semantic purpose other than compile-time checking parameters. Your ultimate goal is to make code more maintainable overall.
You should never have 10 parameters for a method.
Once you have around 4 parameters, begin to consider the use of a new class to contain those parameters... As an example, consider the preferences of a user navigating on a website...
void Main()
{
UserPreferences preference = new UserPreferences
{
BackgroundColor = "#fff",
ForegroundColor = "#000",
Language = "en-GB",
UtcOffSetTimeZone = 0
};
User aydin = new User(preference);
}
public class User
{
public User(UserPreferences preferences)
{
this.Preferences = preferences;
}
public UserPreferences Preferences { get; set; }
}
public class UserPreferences
{
public string BackgroundColor { get; set; }
public string ForegroundColor { get; set; }
public int UtcOffSetTimeZone { get; set; }
public string Language { get; set; }
}
Use an inherited class something like this
class Program
{
static double Func(List<Parent> l) { return l[0]._value * 1000 + l[1]._value * l[1]._value; }
static void Main(string[] args)
{
A a = 1.1d;
B b = 2.2d;
Console.WriteLine(Func(new List<Parent>() {a,b}));
Console.WriteLine(Func(new List<Parent>() { a, b })); // compile-time error! yay!
Console.WriteLine(Func(new List<Parent>() { a, b }) + 123.123d - a * 2); // implicit conversion power
Console.ReadKey();
}
}
class Parent
{
public double _value { get; set; }
}
class A : Parent
{
public static implicit operator A(double value) { return new A() { _value = value }; }
public static implicit operator double(A value) { return value._value; }
}
class B : Parent
{
public static implicit operator B(double value) { return new B() { _value = value }; }
public static implicit operator double(B value) { return value._value; }
}
I don't understand a decision that Visual Studio Express 2013 makes when running the "Extract Method" refactoring. Consider the following code:
public struct Foo
{
private readonly int x, y;
public int X { get { return x; } }
public int Y { get { return y; } }
public Foo(int x, int y)
{
this.x = x;
this.y = y;
}
}
class Test
{
static void Main()
{
Foo a = new Foo(1, 2);
Foo b = new Foo(3, 4);
Console.WriteLine(a);
Console.WriteLine(a + "" + b);
}
}
If I highlight the first Console.WriteLine call and run the Extract Method refactoring, extracting a method called OneParameter, then do the same with the second call extracting a method called TwoParameters, I end up with this code:
class Test
{
static void Main()
{
Foo a = new Foo(1, 2);
Foo b = new Foo(3, 4);
OneParameter(a);
TwoParameters(ref a, ref b);
}
static Foo OneParameter(Foo a)
{
Console.WriteLine(a);
return a;
}
static void TwoParameters(ref Foo a, ref Foo b)
{
Console.WriteLine(a + "" + b);
}
}
Why does the two-parameter method have ref parameters, but not the one-parameter method? What is the point of using ref here?
Also, why does the one-parameter method return Foo?
Both the return and the two refs happen in case the struct is mutable and modified. VS 2013 doesn't really do any analysis of either the struct type for immutability, or the selected code for mutating operations. It doesn't happen for primitives/Guid/etc simply because there is a hard-coded list of value types in the framework that are known to be immutable.
Mostly it comes handy that C# delegates already store the object together with the member function. But is there a way, to store -- and pass as parameters -- only the member function itself, just as the good old pointer-to-member-function in C++?
In case the description is less than clear, I give a self-contained example. And, yes, in the example the insistence to pass around member functions is totally pointless, but I have more serious uses for this.
class Foo {
public int i { get; set; }
/* Can this be done?
public static int Apply (Foo obj, ???? method, int j) {
return obj.method (j);
}
*/
public static int ApplyHack (Foo obj, Func<int, int> method, int j) {
return (int) method.Method.Invoke (obj, new object [] { j });
}
public static readonly Foo _ = new Foo (); // dummy object for ApplyHack
public int Multiply (int j) {
return i * j;
}
public int Add (int j) {
return i + j;
}
}
class Program {
static void Main (string [] args) {
var foo = new Foo { i = 7 };
Console.Write ("{0}\n", Foo.ApplyHack (foo, Foo._.Multiply, 5));
Console.Write ("{0}\n", Foo.ApplyHack (foo, Foo._.Add, 5));
Console.ReadKey ();
}
}
You see, the only workaround I've found is rather ugly and probably slow.
What you want is something called an open instance delegate. I've written about them on my blog
Basically, you can create a delegate to an instance method without tying it to a particular instance, and specify the instance to use it on when you call it:
class Foo {
public int i { get; set; }
public int Multiply (int j) {
return i * j;
}
public int Add (int j) {
return i + j;
}
}
class Program {
static void Main (string [] args) {
Func<Foo, int, int> multiply = (Func<Foo, int, int>)Delegate.CreateDelegate(typeof(Func<Foo, int, int>), null, typeof(Foo).GetMethod("Multiply");
Func<Foo, int, int> add = (Func<Foo, int, int>)Delegate.CreateDelegate(typeof(Func<Foo, int, int>), null, typeof(Foo).GetMethod("Add");
var foo1 = new Foo { i = 7 };
var foo2 = new Foo { i = 8 };
Console.Write ("{0}\n", multiply(foo1, 5));
Console.Write ("{0}\n", add(foo1, 5));
Console.Write ("{0}\n", multiply(foo2, 5));
Console.Write ("{0}\n", add(foo2, 5));
Console.ReadKey ();
}
}
Taking your existing code:
public static int ApplyHack (Foo obj, Func<int, int> method, int j) {
return (int) method.Method.Invoke (obj, new object [] { j });
}
You could do something like this:
public static int ApplyHack (Foo obj, Func<int, int> method, int j) {
var func = (Func<int,int>)Delegate.CreateDelegate(typeof(Func<int,int>), obj, method.Method);
return func(j);
}
This will create a new delegate around the method and the new object. To take your first example:
public static int Apply (Foo obj, ???? method, int j) {
return obj.method (j);
}
The type you are looking for is System.Reflection.MethodInfo and it would look like this:
public static int Apply (Foo obj, MethodInfo method, int j) {
var func = (Func<int,int>)Delegate.CreateDelegate(typeof(Func<int,int>), obj, method);
return func(i);
}
Note that while you are allocating delegates for each invocation, I believe this will still be faster than using reflection, since you do not have to box function input/output, nor store it in object[] arrays.
Assuming you're using C# 2.0 or above, and have access to anonymous delegates, you can do it very simply by wrapping the function in an anonymous delegate at the point of storage:
class Foo
{
public Foo(int v)
{
this.v = v;
}
int v;
public int Multiply(int x)
{
return v * x;
}
public int Add(int x)
{
return v+x;
}
delegate int NewFunctionPointer(Foo, int);
delegate int OldDelegateStyle(int);
static void Example()
{
Foo f = new Foo(2);
Foo f2 = new Foo(3);
// instead of this, which binds an instance
OldDelegateStyle oldMul = f.Multiply;
// You have to use this
NewFunctionPointer mul = delegate(Foo f, int x) { return f.Multiply(x); }
NewFunctionPointer add = delegate(Foo f, int x) { return f.Add(x); }
// But can now do this
mul(f, 4); // = 8
add(f2, 1); // = 3
}
}
If you're okay with passing the this reference as a parameter, why not just use static methods?
class Foo {
public int i;
public static int ApplyHack(Foo foo, Func<Foo, int, int> method, int j) {
return method(foo, j);
}
public static int Multiply(Foo foo, int j) {
return foo.i * j;
}
}
Console.Write("{0}\n", Foo.ApplyHack(foo, Foo.Multiply, 5));
This mainly affects how you construct the Foo object, without changing how you use it. It also doesn't prevent you from having a non-static int Multiply(int) method.
You could retrieve and reuse the MethodInfo for the method or just use the name and extract the method at runtime.
public static int ApplyHack (Foo obj, string methodName, int j)
{
var method = typeof(Foo).GetMethod(methodName);
return (int) method.Invoke (obj, new object [] { j });
}
I'd be very careful that this was actually necessary as it seems like a code smell to me.
You can do it that way
class Foo
{
public int i { get; set; }
public static int Apply(Foo obj, Func<int, int, int> method, int j)
{
return method(j, obj.i);
}
public static int Multiply(int j, int i)
{
return i * j;
}
public static int Add(int j, int i)
{
return i + j;
}
}
static void Main(string[] args)
{
var foo = new Foo { i = 7 };
Console.Write("{0}\n", Foo.Apply(foo, Foo.Multiply, 5));
Console.Write("{0}\n", Foo.Apply(foo, Foo.Add, 5));
Console.ReadKey();
}
I think you can do this easily with this if I understand correctly:
public static int Apply(Func<int, int> method, int j)
{
return (int)method.Method.Invoke(method.Target, new object[] { j });
}
and call it like this:
Console.Write("{0}\n", Foo.Apply(foo.Multiply, 5));