Checking a method call at compile time for multiple parameters of the same type

Here is a 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 becomes a problem if there are methods with many parameters (for example, ten out of double ):

 double Func(double parameter1, double parameter2, ..., double parameter10); 

Question: is there a way to check the parameters when calling the method so that the programmer is less prone to errors?


This is not a problem if the parameter types are different. I thought it might be due to new types:

 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 this is so, but I'm completely not sure if this method is effective. I have doubts if this is a good idea. It? Or is it better there?

I know that I can be absolutely safe if I always call a method like this (using the named arguments method)

 Func(a:a, b:b); 

This should not lead to overhead in the code, but a lot of typing. A wrapper is better because it runs once (creating a new type is easy), but it probably has overhead.

+6
source share
3 answers

If two arguments are of the same type, they cannot be detected at compile time, runtime, or otherwise that the variable name of the argument matches the parameter name. This is a kind of open-ended question, but I will offer you a couple of ideas.

  • As suggested by Mehrzad, we consider the grouping of parameters by 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 could be split?

  • If what you really want to do is do some checking, for example, to ensure that a < b , consider searching for Code Contracts , you can also use Debug.Assert() , but this only works at runtime.

  • I would not recommend suggesting implicit conversion. For me, it feels hacked and unintuitive that A a = 1.1 should not have a semantic purpose, except for the compile-time verification parameters. Your ultimate goal is to make the code easier to maintain.

+4
source

You should never have 10 parameters for a method.

Once you have about 4 options, start looking at using a new class to contain these options ... As an example, consider the preferences of a user navigating 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; } } 
+2
source

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; } } 
0
source

Source: https://habr.com/ru/post/986730/


All Articles