C # optional parameter except zero for class parameter?

What is the best solution to this problem? I am trying to create a function that has several optional class type parameters for which null is a significant value and cannot be used as the default value. As in,

  public void DoSomething (Class1 optional1, Class2 optional2, Class3 optional3)
     {
         if (! WasSpecified (optional1)) {optional1 = defaultForOptional1;  }
         if (! WasSpecified (optional2)) {optional2 = defaultForOptional2;  }
         if (! WasSpecified (optional3)) {optional3 = defaultForOptional3;  }

         // ... do the actual work ...
     }

I cannot use Class1 optional1 = null because null makes sense. I cannot use the instance of the placeholder class Class1 optional1 = defaultForOptional1 due to the constant compile-time constant for these additional parameters. I came up with the following options:

  • Provides overloads with any possible combination, which means 8 overloads for this method.
  • Include a boolean parameter for each optional parameter, indicating whether to use the default value, which I block the signature.

Has anyone out there come up with some kind of smart solution for this?

Thanks!

edit: I ended up writing a wrapper class, so I didn't have to repeat Boolean HasFoo .

  /// <summary> /// A wrapper for variables indicating whether or not the variable has /// been set. /// </summary> /// <typeparam name="T"></typeparam> public struct Setable<T> { // According to http://msdn.microsoft.com/en-us/library/aa288208%28v=vs.71%29.aspx, // "[s]tructs cannot contain explicit parameterless constructors" and "[s]truct // members are automatically initialized to their default values." That fine, // since Boolean defaults to false and usually T will be nullable. /// <summary> /// Whether or not the variable was set. /// </summary> public Boolean IsSet { get; private set; } /// <summary> /// The variable value. /// </summary> public T Value { get; private set; } /// <summary> /// Converts from Setable to T. /// </summary> /// <param name="p_setable"></param> /// <returns></returns> public static implicit operator T(Setable<T> p_setable) { return p_setable.Value; } /// <summary> /// Converts from T to Setable. /// </summary> /// <param name="p_tee"></param> /// <returns></returns> public static implicit operator Setable<T>(T p_tee) { return new Setable<T> { IsSet = true , Value = p_tee }; } } 
+6
source share
5 answers

I would at least think of creating a new type for the parameter:

 public void DoSomething(DoSomethingOptions options) 

... where DoSomethingOptions might look like this:

 public class DoSomethingOptions { private Class1 class1; public bool HasClass1 { get; private set; } public Class1 Class1 { get { return class1; } set { class1 = value; HasClass1 = true; } } ... for other properties ... } 

Then you can call it with:

 DoSomething(new DoSomethingOptions { Class1 = null, Class2 = new Class2() }); 

You do not get an exponential set of overloads, and you can still call it compact enough.

This is similar to the approach that Process takes with ProcessStartInfo .

+10
source

Provide overloads with any possible combination, which means 8 overloads for this method.

This is my preference. This makes the situation very clear and comfortable. Internally, you can map one initialization procedure to reduce duplicate code.

+7
source

I would rather make null mean "nothing" and have a static readonly member of type Class1 , Class2 , etc. on Class1 , Class2 , etc. named None . Then, instead of making null meaningful, you can use null as "nothing" as it was originally intended.

If this is confusing:

 public class Class1 { public static readonly Class1 None = new Class1(); } public static Class2 { public static readonly Class2 None = new Class2(); } 

Note that if null in your case means something other than "No" (for example, "MissingData" or something else), you should call it that way. Also note: this will make much more sense to other people reading and using your code in the future.

+6
source

You can create a Flags enum, which you can pass to mark which classes to use.

 [Flags] public enum DoSomethingOptions { None = 0, UseClass1 = 1, UseClass2 = 2, UseClass3 = 4, etc.. } DoSomething(Class1 class1, ..., DoSomethingOptions options = DoSomethingOptions.None) { ... } 

Then just pass this listing to mark which classes to use. I really wonder why you used null to mean something other than null ? Although this may be a solution, I would really like to say "rethink your design."

+2
source

Yes, try using the object. Define a class that encapsulates the options. When a selection is specified in an object that you can save in the same object if it was set using the installer of the original property.

Example:

 internal class SettingsHolder { public SettingsHolder() { IsOriginalPropADefault = true; } private Class1 originalProp; public Class1 OriginalProp { get { return originalProp; } set { originalProp = value; IsOriginalPropADefault = false; } } public bool IsOriginalPropADefault { get; private set; } } 
+1
source

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


All Articles