Is there a way to make a function use its optional parameter's value? For example, say I have,
public void myFunction(bool required, string optional = "This is optional") {...}
and I want to do something like this,
string possiblyNull = null; // the result of another function
myFunction(true, possiblyNull ?? possiblyNull : optional)
C# compiler embeds the parameter’s default value whenever arguments are left out at the call site. And in your case your want to call your method with that parameter. So, it is not possible, so you have to use that check either outside or inside of your method. If you really want to prevent using if clause while calling your mehtod, then you can change signature of your method so:
public void myFunction(bool required, string optional)
{
optional = optional ?? "This is optional";
...
}
And then call it so:
string possiblyNull = null; // the result of another function
myFunction(true, possiblyNull)
You can't get the default value at the call site. You'd need to have a check outside the method call.
string possiblyNull = null;
// ...
if (possiblyNull == null)
myFunction(true);
else
myFunction(true, possiblyNull);
If your concern is that
You don't want to just make null the default because that would mean the default wouldn't appear in Intellisense and the caller wouldn't see the default
You could make some value the default and then check for null, and if it's null replace it with the default, but that would mean putting the default in two places
You could do this:
private const string OptionalValue = "This is optional!";
public void myFunction(bool required, string optional = OptionalValue)
{
optional = optional ?? OptionalValue;
}
Now you get both. The default shows up in Intellisense and it's not repeated.
If it's just that you
might need to pass a null value
want to get the default value
have to do so frequently enough that it's annoying
can't modify the original method
you could create an extension for the class containing the method:
public static class Extension
{
// I can't think of how this function name would not be awkward.
public static void MyFunctionThatReplacesNullWithDefault(
this ClassWithOptionalMethod target, bool required, string optional = null)
{
if(optional == null)
target.myFunction(required);
else
target.myFunction(required, optional);
}
}
you are quite there but you only need to remove possiblyNull: while you passing the parameter to the method,
you can do like this...
public partial class MainWindow : Window
{
private string optional = "Test";
string possiblyNull = null;
public MainWindow()
{
InitializeComponent();
// here you can check null
myFunction(true, possiblyNull ?? optional);
// Or
myFunction(true);
}
public void myFunction(bool required, string optional = "This is optional")
{
MessageBox.Show(optional);
}
}
Related
When logging data, I want a generic reference to the containing class. That way, if the code is moved elsewhere, the class name will change accordingly. (Otherwise, if the code moves to nameof(Class2), it will still be logged incorrectly as nameof(Class1)). For example:
class Class_Name {
ICommand Command_Name =>
new RelayCommand(() =>
{
// An loggable event occurs
// Is there a smart and uncomplicated way of doing this generically?
var provenance = $"{nameof(Class_Name)}.{nameof(Command_Name)}";
// The event of whatever kind gets logged
});
}
// OR
void Method_Name() {
var provenance = $"{nameof(Class_Name)}.{nameof(Method_Name)}";
}
}
Using a generic nameof(this), where this should refer to the class itself, causes a compilation error: CS8081: Expression does not have a name. Using this.GetType() causes the same problem.
Not really understanding why the this keyword does not refer to the containing class in this context. Is there a way to refer to the current class generically?
If you combine the suggestion in the comments (this.GetType().Name) with a [CallerMemberName] attribute via a helper method, you can accomplish what you're looking for in a reusable fashion.
public class Class_Name
{
public void Method_Name()
{
var provenance = CreateProvenance();
Console.WriteLine(provenance);
}
private string CreateProvenance([CallerMemberName] string methodName = "")
{
return $"{this.GetType().Name}.{methodName}";
}
}
This outputs "Class_Name.Method_Name".
You can even turn this into a handy extension method that allows you to call it from any method.
public class Class_Name
{
public void Method_Name()
{
var provenance = this.CreateProvenance();
Console.WriteLine(provenance);
}
}
public static class ProvenanceExtensions
{
public static string CreateProvenance(this object context,
[CallerMemberName] string methodName = "")
{
return $"{context.GetType().Name}.{methodName}";
}
}
As Jeppe Stig Nielsen pointed out, you may not want the inheriting runtime type to be used, which is what context.GetType().Name will return. If you want to get the compile-time type instead, you can use generics.
public static class ProvenanceExtensions
{
public static string CreateProvenance<T>(this T context,
[CallerMemberName] string methodName = "")
{
return $"{typeof(T).Name}.{methodName}";
}
}
By design:
A nameof expression is evaluated at compile time and has no effect at
run time.
To access the type dynamically, in the runtime, you may use the GetType method. Just rememeber not to combine it with the nameof.
class Class_Name {
void Method_Name() {
// An event occurs
// Is there a smart and uncomplicated way of doing this generically?
var provenance = $"{this.GetType().Name}.{MethodBase.GetCurrentMethod().Name}";
// The event of whatever kind gets logged
}
}
I have this code:
public class NewFrame
{
public NewFrame(string iconSource = Const.Car,
string iconColor = Const.Red)
{
When I try and use it then it's telling me I am missing a default constructor. How can I add one of these and still make the code use the default values for iconBackgroundColor and IconSource? I thought that adding in those defaults with the = Const. would make it work but it seems like it doesn't think my constructor is a default (with no params).
You just have to add another empty overload and call the required constructor with defaults. See below:
public class NewFrame
{
public NewFrame() : this(Const.Car, Const.Red){
}
public NewFrame(string iconSource,
string iconColor)
{
...
}
}
By having two optional parameters, you don't actually create 4 different constructor declarations under the hood (one with both parameters, one with the first parameter, one with the second parameter, and one with neither). There is still only one constructor, with two parameters. It's just that C# recognises that the parameters are optional, and has syntactic sugar to let you omit them when you call the constructor.
However, if you use reflection to create an instance of your class (probably whatever the thing that requires a default constructor is doing), and you attempt to invoke the parameterless constructor, it won't find one, because there is no syntactic sugar in reflection.
Here is an example:
class MainClass
{
public static void Main(string[] args)
{
Type t = typeof(MainClass);
object o = Activator.CreateInstance(t, 1);
Console.WriteLine(o);
}
public MainClass(int a = 10)
{
}
}
If you use typeof(MainClass).GetConstructors(), it will tell you that there is only one.
To actually declare a default constructor, you can do:
public class NewFrame
{
public NewFrame(string iconSource = Const.Car,
string iconColor = Const.Red)
{
...
}
public NewFrame() : this(Const.Car, Const.Red) { }
}
For what it's worth, when I do something like this, I take the route that #VyacheslavBenedichuk's answer is showing.
I'm not sure what your complaint is. This code compiles for me:
public class TestConstructor
{
public TestConstructor(string what = Const.Car, string color = Const.Red)
{
}
public static void Test()
{
var tc = new TestConstructor();
}
public class Const
{
public const string Car = "car";
public const string Red = "red";
}
}
What do your definitions of Const.Car and Const.Red look like? Where are you seeing the error?
But, if you use something that requires a default constructor, then this will not work. For example, this will fail at runtime:
var tc2 = Activator.CreateInstance(typeof(TestConstructor));
Please, when you are reporting an error, describe it exactly - in particular say whether it's a runtime or a compile-time error, the exact wording of the error, and the context in which the error occurs. In this case (the call to CreateInstance) will result in a System.MissingMethodException: 'No parameterless constructor defined for this object.'
In this case, you need to follow #VyacheslavBenedichuk's advice
Using Roslyn, I'm to get the constant value of the following string parameter in this method call:
inst.someMethod($"{Constants.SomeValue}");
static class Constants
{
public static readonly string SomeValue= "some value";
}
I got an instance of InterpolatedStringExpressionSyntax type for the $"{Constants.SomeValue}" parameter.
Next, I need to get its value (which is the "Some value" string), and I tried to call semanticModel.GetConstantValue(expr); but it returns null
How can I get that value?
1) SemanticModel.GetConstantValue works only for compile time constant members, so you cannot use it to get a value of readonly field.
2) If you want to get a value of readonly field you actually need to analyze field initializer and constructors in the common cases to determine where and how this field was created and so on.
But in you simple example above, when you have a static class and static readonly field with initializer you can make something looks ike this:
InterpolatedStringExpressionSyntax interpolatedExpression = // you received it before
// as you know that your member is the first contet of InterpolatedStringExpressionSyntax
var symbolInfo = semanticModel.GetSymbolInfo(((interpolatedExpression).Contents[0] as InterpolationSyntax).Expression);
if (!(symbolInfo.Symbol is null))
{
// assume that exists only a one declaration
var fieldDeclaration = symbolInfo.Symbol.DeclaringSyntaxReferences[0].GetSyntax() as VariableDeclaratorSyntax;
if (!(fieldDeclaration is null))
{
// retrieves text from `SomeValue = "some value"`
var text = (fieldDeclaration.Initializer.Value as LiteralExpressionSyntax)?.Token.Text;
}
}
I have a constant which returns a text for an exception. In this constant I have a placeholder which I have to use. How am I supposed to use this placeholder?
Here is my code:
public static class Messages
{
public const string ShipDestroyed = "{0} has been destroyed";
}
I use the constant in this method in another class:
protected void ValidateAlive(IStarship ship)
{
if (ship.Health <= 0)
{
throw new ShipException(Messages.ShipDestroyed);
}
}
I want to put the "ship.Name" property into the placeholder.
Use String.Format:
throw new ShipException(String.Format(Messages.ShipDestroyed, ship.Name));
If you follow the link, you can see what kind of nice stuff you can do with it.
I have class named "config" that have private string variable named "param".
I need to get from "config" class "param" variable sometimes as int type sometimes as bool type or string.
As I understand I need create 3 properties in config class,each property have to convert type, as follow:
The first property converts string to int, the second converts string to bool, the third property gets me the string value.
The class should look something like this:
class Config
{
private string param;
public int ParamAsInt
{
get
{
return int.Parse(param);
}
}
public bool ParamAsBool
{
get
{
return bool.Parse(param);
}
}
public string ParamAsString
{
get
{
return param;
}
}
}
But I don't know how can those properties be used in accordance to the variable type that I want to get out of class.
This code won't compile - int and such are reserved keywords and cannot be used as identifiers. You can either try naming your properties something like Int32Value, StringValue, etc., or try this:
public static implicit operator bool (Config config)
{
return bool.Parse(config.param);
}
public static implicit operator int (Config config)
{
return int.Parse(config.param);
}
This will allow for much cleaner code:
Config c = GetConfig("foo");
var isFeatureEnabled = false || c;
var spacing = 23 + GetConfig("bar");
You forgot to give your properties names. How would you expect to reference them? Something like this:
class Config
{
private string param;
public int ParamAsInt
{
get
{
return int.Parse(param);
}
}
public bool ParamAsBool
{
get
{
return bool.Parse(param);
}
}
public string ParamAsString
{
get
{
return param;
}
}
}
Note that I also fixed the casing in your calls to .Parse(). C# is case-sensitive. I also replaced the call to bool.TryParse() with bool.Parse(). The former (when used correctly, which this wasn't because it was missing a parameter) will only tell you if it is a bool, it won't tell you what value the bool actually has. (For example, bool.TryParse('false' out someBool) will return true.)
Of course, this code is a bit dangerous. You'll want to start with some more defensive programming to check those values. Basically, look up TryParse() and how to use it correctly. Something like this, for example:
public int ParamAsInt
{
get
{
var tmp = default(int);
if (int.TryParse(param, out tmp))
return tmp;
else
// do something else? throw a specific exception?
}
}
Additionally, what is the purpose of this code? It seems like a very rushed and poor design. For any given value of param (how is that even being set, by the way?) this just sort of randomly tries to expose typed properties for it. If you guess the correct one, you're still left with others that will throw exceptions. Surely there's a much cleaner way to accomplish what you're trying to do. So what are you trying to do?