1

I am using Visual Studio 2013 and .Net 4.5 with C#.

Is it possible to dictate that a parameter of a method must be "stringA" or "stringB" witohut introducing a new class with constants or enums. and that the compiler gets a warning or copile error when this parameter dont fit the restriction.

I thought something like this:

public void SomeMethod(string param1) : Allowed param1 = ("stringA" || "stringB")
{
  //Do something.
}

So that I am not able to do this:

this.SomeMethod("stringC"); <-- this must be a compile error 

Is there a function or possibility I can do this nicely?

anar khalilov
  • 16,993
  • 9
  • 47
  • 62
damir
  • 1,928
  • 1
  • 16
  • 26
  • Why would you need this though? if you can see the method does not allow a certain value, don't parse that value to the method. – string.Empty Jan 08 '14 at 09:59
  • Thanks all for your help, i thought that this is maybe not possible, i would like the answer from @StuartLC, but i need a compile error, just a warning is not enough for me.. i thought first to use Enum, but i thought to use something maybe new for me :) to learn new stuff :) thanks again for all your help.. – damir Jan 08 '14 at 10:01

7 Answers7

2

I think (not sure, never read or seen) it is not possible the way you are looking. But obviously you can handle all the invalid input in your method and return for invalid inputs. I don't know why you don't want to introduce enum here, but it would be a good way.

Ehsan
  • 31,833
  • 6
  • 56
  • 65
  • i am since 2 months in this project, and there are a lot of very similar enums out there, and i thougt, that i do not also create a new one with again some similar enums, but i will have to do it, much cleaner than i thought :) – damir Jan 08 '14 at 10:05
2

you can't do that. Better use Enumeration or custom type as a parameter. That will make your validation possible at compile time.

realnero
  • 994
  • 6
  • 12
1

Essentially, no.

You could do

public void SomeMethod(string s)
{
    switch (s)
    {
        case "stringA":
        case "stringB":
            break;

        default:
            throw new ArgumentException("Value invalid.", "s");
    }

    // Do something.
}

but, I'd suggest its better to use an enum, as you state.

Enum PointlesslyArbritary
{
    A,
    B
}

public void SomeMethod(PointlesslyArbritary e)
{
    // Do something.
}

Its not much of a burden and makes usage much clearer to the caller and compiler. On consideration, this enum is "nicer" than the approach you suggest.

Jodrell
  • 34,946
  • 5
  • 87
  • 124
  • After thinking about it, i will use the enum version. this was also my first choice, but i thought i could do it similar what @StuartLC said. but with compile error. not everybody looks on warnings, so its better to have an compile error. With enum i can force the user of method to use just what i can support. – damir Jan 08 '14 at 09:59
1

It is not possible to check parameters compile time because the compiler don't know what is coming in following case:

string value = Console.In.Readline();
SomeMethod(value); // How does compile know what is given to SomeMethod

Besides that, if behavior depends on string variables I would consider to refactor or to use proper error handling.


3 ways to refactor:

1: Use enums: Compile time errors

public enum MyInputEnum { Input1, Input2 }

public void SomeMethod(MyInputInum value) { .. }

SomeMethod(MyInputEnum.Input2); // Compiles
SomeMethod(MyInputEnum.Input3); // Compile Error because Input3 not defined

2: Use interfaces: Compile time errors

public interface IInputDescription { }
public class InputClass1 : IInputDescription { .. }
public class InputClass2 : IInputDescription { .. }
public class ErrorClass { .. } // This example class does not implement IInputDescription

public void SomeMethod(IInputDescription value) { .. }

SomeMethod(new InputClass2()); // Compiles
SomeMethod(new ErrorClass()); // Compile error

3: Use Error handling: Runtime errors

// Option 1
public void SomeMethod(string value)
{
    if(!value.Equals("StringA") && !value.Equals("StringB")) 
        throw new ArgumentException("Invalid argument");
    ...
}

// Option 2
public void SomeMethod(string value)
{
    switch(value)
    {
        case "StringA": 
            ... 
            break;
        case "StringB": 
            ... 
            break;
        default:
            throw new ArgumentException("Invalid argument");
    }
}
hwcverwe
  • 5,287
  • 7
  • 35
  • 63
1

You can use a Contract.Requires using code contracts:

public void SomeMethod(string param1)
{
   Contract.Requires(param1 == "stringA" || param1 == "stringB");
}

You won't necessarily get a compile time error, but if you turn on static checking, you will get a warning if a caller doesn't match this contract.

StuartLC
  • 104,537
  • 17
  • 209
  • 285
  • I learnt something from this, its simpler to write and shows obvious intent compared to an `if` or `switch`. – Jodrell Jan 08 '14 at 10:02
  • i tested this, but this line is always skipped?! and in hover it is said that this method invocation will be skipped because it is conditional or have a partial method without implementation?! – damir Jan 08 '14 at 10:12
  • @ku5ar You'll need to install the appropriate VS Extension [VS2010](http://blogs.msdn.com/b/bclteam/archive/2010/01/26/i-just-installed-visual-studio-2010-now-how-do-i-get-code-contracts-melitta-andersen.aspx) or [2012](http://stackoverflow.com/questions/13434695/code-contracts-doesnt-seem-to-work-on-vs2012), then go into the `project properties` | `Code Contracts` tab and select `perform static contract checking` – StuartLC Jan 08 '14 at 10:51
0

Also think to better use compile time and create validation inside function. I don't know if it is possible to use Attributes for doing your job but then it use runtime.

mike00
  • 438
  • 1
  • 6
  • 17
0

You can use some kind of validation to let the method know what you are sending, for example:

public enum AllowedParams
{
        StringA = 2,
        StringB = 4,
        StringC = 8,
}

public void SomeMethod(string param1, AllowedParams SentParam)
{
    if (SentParam.HasFlag(AllowedParams.StringA) | SentParam.HasFlag(AllowedParams.StringB))
    {
    }
}

Call the method like this,

SomeMethod("str", AllowedParams.StringC);

Obviously this is not what you want, but C# or .net for that matter can not do what you want.

The compiler does not know the value of what will be sent to the method. These things do not happen at compilation, The only thing the compiler knows is the ParameterInfo of the parameter. It uses that to determine if it is a valid parameter.

string.Empty
  • 10,393
  • 4
  • 39
  • 67