Is it possible to restrict the values of optional parameters in C#? - c#

C# allows the use of optional parameters: one can specify the value in case the parameter is omitted in a call and the compiler then specifies the value itself.
Example:
public interface IFoo {
void SomeMethod (int para = 0);
}
This idea is useful but a problem is that one can define several "default values" on different levels of the class hierarchy. Example:
public class SubFoo : IFoo {
public void SomeMethod (int para = 1) {
//do something
}
}
If one later calls:
SubFoo sf = new SubFoo ();
sf.SomeMethod ();
Foo f = sf;
f.SomeMethod ();
The result is that the first call is done with para equal to 1 and the second with para equal to 0 (as interface). This make sense since the compiler adds the default values and in the first case the this is a SubFoo thus the default value is 1.
It is of course up to the programmer to maintain consistency, but such schizophrenic situations can easily occur when a programmer changes his/her mind in the middle of the process and forgets to modify all default values.
Problematic is that the compiler doesn't warn that different default values are in use whereas this can be checked by moving up the class hierarchy. Furthmore some people might mimic default parameters with:
public class SubFoo2 {
public virtual void SomeMethod () {
SomeMethod(1);
}
public void SomeMethod (int para) {
//do something
}
}
Which allows dynamic binding and thus overriding consistently. It thus requires one to be very careful with how default values are "implemented".
Are there ways to enforce (with compiler flags for instance) to check whether the default values are consistent? If not it would be nice to have at least a warning that something is not really consistent.

Well not necessary compile-time solution - but you can make unit test for that (I suspect that you're taking seriously unit testing and you run them frequently if you ask this kind of question). The idea is to create assertion method like AssertThatDefaultParametersAreEqual(Type forType) - find all classes that are not abstract (using reflection) and inherit from forType then iterate over all methods which have defined default parameters:
MethodInfo[] methodInfo = Type.GetType(classType).GetMethods(BindingFlags.OptionalParamBinding | BindingFlags.Invoke);
Group them by MethodInfo.Name and check does within the group all same parameters with default values (could be obtained by MethodInfo.GetParameters().Where(x => x.IsOptional)) have the equal property of ParameterInfo.DefaultValue.
edit: btw. that might not work in Mono because compilers aren't obligated to emit for instance: Optional BindingFlag.

If you want to have a compile time indication that a method is changing the default value of an optional argument, you're going to need to use some sort of 3rd party code analysis tool, as C# itself doesn't provide any means of providing such a restriction, or any warnings when its done.
As a workaround, one option is to avoid using optional parameter values and instead use multiple overloads. Since you have an interface here, that would mean using an extension method so that the implementation of the overload with a default value is still defined in the general case:
public interface IFoo
{
void SomeMethod(int para);
}
public static class FooExtensions
{
public static void SomeMethod(this IFoo foo)
{
foo.SomeMethod(0);
}
}
So while this approach does technically still allow someone to create an extension (or instance) method named SomeMethod and accepting no int argument, it would mean that someone would really need to go out of their way to actively change the "default value". It doesn't require implementations of the interface to supply the default value, which risks them unintentionally providing the wrong default value.

Define const int DefaultPara = 1; and then use that instead of hard coding numerical values.
interface IFoo
{
void SomeMethod (int para = DefaultPara);
}
public class SubFoo : IFoo {
public void SomeMethod (int para = DefaultPara) {
//do something
}
}

Related

C# optional parameters: Why can I define the default different on interface and derived class?

With C#, we now can have optional parameters, and give them default values like this:
public abstract class ImporterBase : IImporter {
public void ImportX(bool skipId = true) {
//....
}
}
Now, suppose in the interface we derive from, we have
public interface IImporter {
void ImportX(bool skipId = false);
}
See, that the default value is defined as different in the base class as in the interface. This is really confusing, as now the default value depends whether I do
IImporter interfaceImporter = new myConcreteImporter(); //which derives from ImporterBase
interfaceImporter.DoX(); //skipId = false
or
ImporterBase concreteImporter = new myConcreteImporter(); //which derives from ImporterBase
concreteImporter.DoX(); //skipId = true
Why is it allowed to define the default value differently in both the interface and the derived class?
Note: this question similar, but focuses on the optionality, not on the value.
To clarify, I'm interpreting the question to be:
If a method is defined in an interface / base class which has a method which has a parameter with a default value, and a class implements / overrides that method but provides a different default value, why doesn't the compiler warn?
Note that this doesn't cover the case where the implementation doesn't provide any default value -- that case is explained by Eric Lippert.
I asked this on the csharplang gitter channel, and the response from someone who has been heavily involved in the language design for a long time was:
i think an analyzer sounds very good for this.
From that, and the other links posted here (which don't even mention this specific case), my best guess is that this specific case just wasn't considered, or was briefly considered but dismissed as too niche. Of course, once C# 4 was released, there was no way to add a compiler error or warning without breaking backwards compatibility.
You could write an analyzer which catches this case (which had a code fix to correct the default value), and try to get it incorporated into Roslyn.
As a footnote, there are a few cases I can see which would cause issues.
An interface changes the default value for one of its parameters
This is already a binary-breaking change, and this would promote it to a source-breaking change.
Two interfaces with different default values
interface I1
{
void Foo(bool x = false);
}
interface I2
{
void Foo(bool x = true);
}
class C : I1, I2
{
...?
}
If you did want to specify a default value for C.Foo, this case could be solved by explicitly implementing one of the interfaces:
class C : I1, I2
{
public void Foo(bool x = false) { ... }
void I2.Foo(bool x) => Foo(x);
}
Alternatively you could just ignore this case, and not warn.
Adding an interface in a child class
interface I1
{
void Foo(bool x = false);
}
class Parent
{
public void Foo(bool x = true) { ... }
}
class Child : Parent, I1
{
...?
}
I'm not sure what an intuitive solution to this would be, but since it's so niche I'd be tempted just to ignore it, and not warn.
There's a good reason for it. See here.
The short answer is though, if it treated the optional values as part of the method signature, it cause some problems. Imagine the code below:
public abstract class A
{
public abstract void SomeFunction(bool flag);
}
public class B : A
{
public override void SomeFunction(bool flag = true)
{
//do something
Console.WriteLine(flag);
}
}
If the optional parameter value was part of the method signature then I'd get a compilation error since A doesn't have bool flag = true in the method signature. It's an easy fix for sure but if you shipped A to a third party and their custom code created class B, they'd have to go change your code to have the optional parameter. Also keep in mind this is exacerbated when there are several levels of inheritance. So the easiest fix was to not consider the optional parameter value as part of the method signature for these purposes.

Using methods from a type passed as a parameter in C#

I'm working in Q#, a quantum programming language based on C#. Quantum operations become C# classes, from which you can do things like
QuantumOperation.run(simulator, param1, param2);
which will use a quantum simulator simulator to run the operation QuantumOperation with the parameters param1 and param2.
I have many different operations which I want to run using different simulators and different parameters. What I would like to do is pass the quantum operation to another method, which will iterate through all the simulators and parameters. Then I can call this method with all the quantum operations I want.
The problem is that - as far as I can tell - a quantum operation is really a class and not an object. So, for example, if I write:
static void someMethod<Qop>(){...}
then I can call this with a quantum operation QuantumOperation as:
someMethod<QuantumOperation>()
and it compiles fine. However, if I try to do something like
static void someMethod<Qop>(Qop quantumOperation){ ...}
someMethod<QuantumOperation>(quantumOperation);
I get an error of "QuantumOperation is a type, which is not valid in the given context" for the second line.
If I try:
static void someMethod<Qop>(...){
...
Qop.Run(...);
...
}
it similarly says: "'Qop' is a type parameter, which is not valid in the given context".
What seems to be happening here is that I'm passing the class as a type. But then when I want to treat the type as a class, I can't. I looked for ways to pass a class as an argument, but I only see ways to do this that will create objects in that class. But I can't use an object, since "Run" is a static method.
(I could try passing an object and getting the class from that, but (a) I don't know if it's possible to create objects of quantum operation classes, and (b) I can only find public Type GetType, which returns a type and not a class, giving the same problem).
Is there any way to pass a class as an argument, then reference static methods of that class, without ever instantiating an object?
Now, maybe I'm asking too much, since, as far as C# is concerned, it's a coincidence that all these classes have a method called "Run". It maybe shouldn't be able to attempt to call methods with the same name from different classes.
Alternatively, I could construct a method for each quantum operation and then pass those methods. The method would look like:
static void QuantumOperationWrapper(QuantumSimulator simulator, Int int_parameter){
QuantumOperation.Run(simulator, in_parameter);
}
I would need to make a new method for each quantum operation, but that's not that bad. Then I can pass this as a delegate or Func to the methods I want. The problem is that the results I want are contained in the QuantumSimulator object. So what I want to do is something like:
QuantumOperationWrapper(simulator, 3);
simulator.GetResults();
But when I do this, the results are empty. My guess is that, somehow, the simulator is being passed by value, or treated as immutable, or something that prevents QuantumOperationWrapper from altering internal parameters of the simulator.
Is there any way to I can ensure that a delegate/Func will alter the internal state of its arguments?
EDIT: I can make a delegate for the Run method, as follows:
public delegate System.Threading.Tasks.Task<Microsoft.Quantum.Simulation.Core.QVoid> RunQop(QCTraceSimulator sim, long n);
Then I can construct static void someMethod(RunQop runner, ...), and pass QuantumOperation.Run as the first argument.
However, I have the same problem, that the QCTraceSimulator I pass as an argument does not keep any of the simulation results it makes when I call this.
So if I understand you correctly you want to execute a bunch of methods with parameters on different simulators. Here is how to do this:
We first off need a List of the operations we want to perform.
var methodList = new List<Func<QCTraceSimulator, long, Task<QVoid>>>
{
QuantumOperation.Run,
// Add more methods here
}
This is a List of Funcs. A Func is a delegate type that represents a method with a parameter and a return value. Here our methods need to look like this to be able to be added to our List:
public Task<QVoid> SomeName(QCTraceSimulator sim, long parameter)
{ ...}
We also need a list of parameters you want to try this with:
var paramsList = new List<long>
{
1,
2,
-2147483648,
2147483647
};
Now we can iterate through these and run our method like so:
public void RunMethodsOnSimulator(QCTraceSimulator sim)
{
// Iterate through every method
foreach (var method in methodList)
{
// Iterate through every parameter
foreach (var parameter in paramsList)
{
// Execute the given method with the given parameter
Task<QVoid> result = method(sim, parameter);
}
}
}
You can now do whatever you want with the result. This will result in every method being called with every parameter once
Please keep in mind that this answer only solves this problem for methods that return a Task<QVoid> and take a QCTraceSimulator and a long as parameter. This solution however avoids having to modify any QuantumOperation classes (and hopefully teaches you a little about delegates)
Here is what the paramsList and the RunMethodsOnSimulator method would like with 2 or more parameters:
methodList = new List<Func<QCTraceSimulator, long, int, Task<QVoid>>>
{
QuantumOperation.Run,
// Add more methods here
}
paramsList = new List<Tuple<long, int>>
{
new Tuple<long, int>(1, 1),
new Tuple<long, int>(2, 1),
new Tuple<long, int>(1, 2),
new Tuple<long, int>(-2147483648, 1)
}
public void RunMethodsOnSimulator(QCTraceSimulator sim)
{
// Iterate through every method
foreach (var method in methodList)
{
// Iterate through every parameter
foreach (var parameter in paramsList)
{
// Execute the given method with the given parameter
Task<QVoid> result = method(sim, parameter.Item1, parameter.Item2);
}
}
}
The way the Q# simulation tests deal with this is by having a method that receives a delegate with some code you want to execute on the simulator, in particular, the simulator unittests have the RunWithMultipleSimulators method that is broadly used in places like CoreTests.cs; this is an example of how it is used:
[Fact]
public void RandomOperation()
{
Helper.RunWithMultipleSimulators((s) =>
{
Circuits.RandomOperationTest.Run(s).Wait(); // Throws if it doesn't succeed
});
}
I think you're having two separate problems: you're not getting the results back, and dealing with classes is making looping through different operations difficult. Let me try to address them separately.
Results from running an operation are returned from the Run method, not stored in the simulator. More specifically, if you invoke an operation that returns a Q# int, the return value of the Run method will be Task<long>. You can then use the value property of the task to get the actual result, or use the async/await pattern, whichever you like.
All of the operation classes can be instantiated, and they all implement the ICallable interface. This interface has an Apply method that gets passed the arguments to the operation and returns the (asynchronous) results. Each instance has to get properly instantiated with a reference to the simulator; the easiest way to do this is to call the Get generic method on the simulator instance.
If you look at SimulatorBase.cs, in the implementation of the Run method on line 101, you can see how this is done. In this method, T is the class of the operation; I is the class of the operation input; and O is the class of the operation return value. You could use basically the same code to create a list of objects that you then call Apply on with varying arguments.
I did not understand everything but from the little that I understood you can use a non static wrapper and each wrapper allows accessing to a distinct Qop static class.
static public void TestQop()
{
someMethod(new Qop1(), 0, 0, 0);
someMethod(new Qop2(), 1, 1, 1);
}
static void someMethod<T>(T qop, int simulator, int param1, int param2)
where T : QopBase
{
qop.Run(simulator, param1, param2);
}
abstract class QopBase
{
public abstract void Run(int simulator, int param1, int param2);
}
class Qop1 : QopBase
{
public override void Run(int simulator, int param1, int param2)
{
QuantumOperation1.Run(simulator, param1, param2);
}
}
class Qop2 : QopBase
{
public override void Run(int simulator, int param1, int param2)
{
QuantumOperation2.Run(simulator, param1, param2);
}
}
Calling a method on an object whose type is generically defined requires you to use a generic constraint which ensures that the used generic type defines the expected method.
At its core, this relies on polymorphism to ensure that even though the specific type can vary, it is known that all usable generic types (which can be limited via constraints) contain this specific method you wish to call.
Static classes and methods lack this feature. They cannot inherit, nor can they implement interfaces, nor can you pass them via method parameters (and trying to do it via generic is not the solution). There is no way to create an "inheritance-like" link between two static methods of two different static classes; even if the methods have the same signature otherwise.
Are there other ways? Yes. In order of preferability:
(1) The straightforward and clean solution is avoiding statics and instead use instanced classes. If you are able to do this, this is the superior option.
(2) If you can't avoid statics, you can still wrap your static in an instanced wrapper, e.g.:
public class IWrapper
{
void DoTheThing(int foo);
}
public QuantumOperationWrapper : IWrapper
{
public void DoTheThing(int foo)
{
QuantumOperationWrapper.Run(foo);
}
}
public OtherStaticOperationWrapper : IWrapper
{
public void DoTheThing(int foo)
{
OtherStaticOperationWrapper.Run(foo);
}
}
This effectively "unstatics" the static code, in a way that you can now rely on the knowledge that all your wrappers implement/inherit the common BaseWrapper and thus both implement the DoTheThing method.
Your generic method can then rely on this:
public void DoTheGenericThing<T>(T obj) where T : IWrapper
{
obj.DoTheThing(123);
}
Note: In this particular case you don't even need generics to begin with. I assume you don't really need generics in this case, but since the answer can apply to both generic and non-generic cases, I've left the generic parameter in the solution. There may be specific cases in which you still need to use generics, though I suspect this is not one of them.
(3) A third but very dirty option is to use reflection to call the method anyway and just assume you never pass in a type which does not have the expected static method. But this is a really bad practice approach which will be fraught with bugs, it will be nigh impossible to debug, and it's absolutely not refactor-friendly.
Maybe you can try to deal with the situation using Interfaces. Something like that:
public interface IQuantumOperation
{
void Run();
void Run(MyFancyClazz simulator, MyFancyParam param1, MyFancyParam param2);
//And other possible methods
}
Then you can make use of this Interface as a type parameter's contract
static void someMethod<Qop>(Qop myQopParameter) where Qop : IQuantumOperation
{
...
//Now you can call your Run method
myQopParameter.Run(...);
...
//Or other fancy Run method with parameters like below
myQopParameter.Run(simulator, param1, param2);
}
Finally make sure that your QuantumOperation class implements the IQuantumOperation interface

Call any class sharing the same method name in C#

I have a significant number of classes which share the same method name, but don not share a common base/interface. I cannot touch these classes, however, can I call the method irrespective of the defining class?
Eg:
Namespace n1: class A { void M1(n1.CustObj ob1){} }
Namespace n2: class B { void M1(n2.CustObj ob1){} }
Would it be possible to abstract from these common methods/parameters, like so?
method(Object obj)
{
obj.M1(new CustObj() {
x = 3;
}); // CustObj can either belong to n1 or n2
}
You have a number of classes, each of which has a method, with the same name, but with a different signature. The identical method names are a red herring here therefore as they are different methods.
This therefore rules out using dynamic or reflection to provide a single method that can handle all of them, unless you then hard-code tests for each type within the one method, or take Jonathan Wood's approach of passing in an existing instance of CustObj via a dynamic parameter too.
One solution might be to create extension methods for each type:
public void Method(this A obj)
{
obj.M1(new n1.CustObj()
{
x = 3
});
}
public void Method(this B obj)
{
obj.M1(new n2.CustObj()
{
x = 3
});
}
and so on. Then at least you can do someObj.Method(); on A, B and so forth.
You could use either the dynamic keyword or reflection.
Of the two, I prefer dynamic. However, since your constructor argument is also a different type you'd need to do something like this:
void method(dynamic obj, dynamic arg)
{
arg.x = 3;
obj.M1(arg);
}
I understand it's unlikely that your code is set up to do this but you haven't shown much of how your method is used. And in the end, this might be the best you can do if you're unable to modify the existing classes.

How can I guarantee that an interface and a class method parameters match without manually checking?

I recently noticed a bug due to a mismatched parameter order in the class to its interface parameter order. I felt that this should have been a compile error. I found out that Interfaces do not constrain the parameter names. So if you see my example below I have firstParameter and secondParameter reversed, I also have parameterOne and parameterTwo, both as valid builds. This may build just fine, but you will likely run into runtime errors.
On the other hand, it does require the order of the types of the parameters to match. So I thought perhaps I do not need to place the parameter names in the interface and just the value types, but that does not work and the interface would still need to provide a description of what the types are in terms of what a consumer would place there.
My Question
Is there a way to guarantee at build time that a class matches the interface parameter names? I would prefer not to do this manually.
The reason this is important is even though the method variables cannot be setup to be used by the interface, someone consuming a service reference or other use of an interface would see the Interface parameters at the time of setup and that is the expected use of the parameters. If I cannot rely on a contract to be exact, what is the point of a contract in the first place?
interface IParameterTest
{
void TwoStringParameters(string firstParameter, string secondParameter);
void TwoStringParametersAndAnInt(string firstParameter, string secondParameter, int thirdParameter);
}
public class ParameterTest : IParameterTest
{
//Builds and matches interface
//public void TwoStringParameters(string firstParameter, string secondParameter)
//{
// throw new NotImplementedException();
//}
//Builds and does not match interface
//public void TwoStringParameters(string secondParameter, string firstParameter)
//{
// throw new NotImplementedException();
//}
//Builds and does not match interface
public void TwoStringParameters(string parameterOne, string parameterTwo)
{
throw new NotImplementedException();
}
//Builds and matches interface
public void TwoStringParametersAndAnInt(string firstParameter, string secondParameter, int thirdParameter)
{
throw new NotImplementedException();
}
//Does not build or match interface
//public void TwoStringParametersAndAnInt(int firstParameter, string secondParameter, string thirdParameter)
//{
// throw new NotImplementedException();
//}
}
Is there a way to guarantee at build time that a class matches the interface parameter names? I would prefer not to do this manually.
Not within the C# language. However:
You could write a unit test to check, reasonably easily. Not quite build time, but still early enough to catch errors before they're big problems.
You could write a Roslyn code diagnostic to flag it as an error (and even provide a code fix for it).
Of course, the unit test could be written via Roslyn as well, but you could do it fairly easily just using plain reflection.
It's not entirely clear from your question whether you've spotted the really nasty problem with parameter names being wrong, by the way - it's not just in terms of human readability, but it can significantly affect behaviour if you use named arguments. For example, suppose you have code like this:
public interface IFoo
{
void Foo(int x, int y);
}
public class FooImpl : IFoo
{
public void Foo(int y, int x) { ... }
}
...
IFoo foo = new FooImpl();
foo.Foo(x: 10, y: 20); // Equivalent to foo.Foo(10, 20)
Now if someone decides to use var instead, the compile-time type of foo is changed, so suddenly the named arguments map to different parameters.
var foo = new FooImpl();
foo.Foo(x: 10, y: 20); // Equivalent to foo.Foo(20, 10)
Perfectly valid code... but with a different meaning to the previous code. There are other times that changing the compile-time type of a variable can affect things, but that's usually around overloading etc... this is in the simple case where there really is just one method.
As Jon says, C# doesn't really care what the parameters are called, but if you wanted to reflectively assert the parameter names for yourself; either at start up or in a unit test, you could use something like this:
public class Program
{
public static void Main(string[] args)
{
var assembly = Assembly.GetAssembly(typeof(Program));
var types = assembly
.GetTypes()
.Where(x => x.IsClass && x.GetInterfaces().Any());
foreach (var type in types)
{
var interfaces = type.GetInterfaces().Where(x => x.Assembly == assembly);
foreach (var iface in interfaces)
{
var classMethods = type.GetMethods();
foreach (var interfaceMethod in iface.GetMethods())
{
var classMethod = classMethods.First(x => x.ToString() == interfaceMethod.ToString());
Debug.Assert(
interfaceMethod.GetParameters().Select(x => x.Name).SequenceEqual(classMethod.GetParameters().Select(x => x.Name)),
"Incorrect parameter names in method: " + type.Name + "." + classMethod.Name);
}
}
}
}
public interface ITest
{
void MethodA(string first, string second);
}
public class TestA : ITest
{
public void MethodA(string first, string second) { }
}
public class TestB : ITest
{
public void MethodA(string second, string first) { }
}
}
FxCop already has a rule to enforce this. You can enable code analysis to run on build in your project properties, then configure the code analysis rule set to treat that warning as an error. If you integrate that into your build process you will force all your developers to address that issue before their builds will succeed.
Yes, you have a few build-time alternatives. You'd have to weigh whether they are worth the effort.
create a custom static code analysis rule (what used to be FxCop)
use Roslyn and plug it into MSBuild
something completely custom plugged into MSBuild that fails the build if you don't have a match
Your question
If I cannot rely on a contract to be exact, what is the point of a contract in the first place?
is worth considering, however names of required parameters as contractual requirement may be considered quite narrow. There is a compile-time way to fix this, and you've even suggested it in your question: you are bound by the order, number and type of parameters. If you needed a very strict interface, you could abstract the parameters by wrapping the simple types, preventing a case such as accidental argument swapping.
Again, you'd have to weigh whether it's worth it. You're buying interface safety at the cost of more code and cognitive load.
In this case I would suggest a much better solution is to refactor the interface to use the parameter object design pattern rather than messing around with enforcing the parameter names of two strings are implemented in the correct order.
Example if string 1 was "firstName" and string 2 was "lastName" you are much better off with a class with two properties FirstName and SecondName and then have your interface depend on this parameter object rather than low level data types such as strings.

How to call overridden method which have overloads?

I have the following simple code
abstract class A
{
public abstract void Test(Int32 value);
}
class B : A
{
public override void Test(Int32 value)
{
Console.WriteLine("Int32");
}
public void Test(Double value)
{
Test((Int32)1);
}
}
When I ran this code the line Test((Int32)1) causes stack overflow due to infinite recursion. The only possible way to correctly call proper method (with integer parameter) I found is
(this as A).Test(1);
But this is not appropriate for me, because both methods Test are public and I am willing the users to be able to call both method?
Method overload resolution in C# does not always behave as you might expect, but your code is behaving according to the specification (I wrote a blog post about this a while ago).
In short, the compiler start off by finding methods that
Has the same name (in your case Test)
are declared in the type (in your case B) or one of its base types
are not declared with the override modifier
Note that last point. This is actually logical, since virtual methods are resolved in run-time, not compile time.
Finally, if the type (in this case B) has a method that is a candidate (which means that the parameters in your call can be implicitly converted to the parameter type of the candidate method), that method will be used. Your overridden method is not even part of the decision process.
If you want to call your overridden method, you will need to cast the object to its base type first.
Unfortunately in order to call the A::Test(int) through a B reference some sort of cast is needed. So long as the C# compiler sees the reference through B it will pick the B::Test(double) version.
A slightly less ugly version is the following
((A)this).Test(1);
Another thought though is have a private method with a different name that both feed into.
class B : A {
public override void Test(int i) {
TestCore(i);
}
public void Test(double d) {
TestCore(1);
}
private void TestCore(int i) {
// Combined logic here
}
}

Categories

Resources