I have seen two approaches to setting a property as nullable. What is the difference between the two approaches? which one is clean?
public string? a { get; set; };
public string b { get; set; } = default!;
Edit 1: Updated code to correct syntax and changed int -> string
You wrote int a?instead of int? a.
The 2 behave very differently here. An int is not nullable, its default value is 0. Therefore you can just use defuslt without the ! . The ! just makes the compiler ignore null check rules.
The other creates a real null value.
Lets say we instead had:
string? a = null
Or
string a = default!
Which behave almost the same, but their type differs.
In that case the ? nullable reference type is more clean as you dont get rid of the null safety guarantees.
The first approach is correct so to say.
You can understand this clearly using snippet as below.
void Main()
{
var pro = new Pro{
a = 1,
//b = 1
};
Console.WriteLine(typeof(int));
Console.WriteLine(typeof(int?));
}
public class Pro {
public int? a { get; set; }
public int b { get; set; } = default!;
}
Related
I've currently got a class that has multiple string properties. One or more of them may have a value. What I need to do is get the first non-empty property, based off some priority. Here is an example of what I envision the class would look like:
public class MyClass
{
[Priority(1)]
public string HighestPriority { get; set; }
[Priority(2)]
public string MiddlePriority { get; set; }
[Priority(3)]
public string LowestPriority { get; set; }
}
Or, maybe use another enum property that can be used to determine the highest one that is set?
public enum Priority
{
HighestPriority,
MiddlePriority,
LowestPriority
}
public class MyClass
{
private string highestPriority;
public string HighestPriority
{
get;
set
{
highestPriority = value;
HighestSetProperty = Priority.HighestPriority;
}
}
private string middlePriority;
public string MiddlePriority
{
get;
set
{
middlePriority = value;
if (HighestSetProperty != Priority.HighestPriority)
HighestSetProperty = Priority.MiddlePriority;
}
}
private string lowestPriority;
public string LowestPriority
{
get;
set
{
lowestPriority = value;
if (HighestSetProperty != Priority.HighestPriority || HighestSetProperty != Priority.MiddlePriority)
HighestSetProperty = Priority.LowestPriority;
}
}
public Priority HighestSetProperty { get; set; }
}
Then, use HighestSetProperty to set the string in a switch statement?
So far though, the only way I know of to find the first non-empty property, without using some form of priority attribute like above, is something like this:
string highestPriorityProp = String.IsNullOrWhitespace(HighestPriority) ? (String.IsNullOrWhitespace(MiddlePriority) ? LowestPriority : MiddlePriority) : HighestPriority;
Which is obviously messy and doesn't scale well if more properties are added.
So, what is the best way (in terms of readability, speed and scalability) of doing this? Thanks in advance.
EDIT: Let's go for cleanliness and scalability over speed.
EDIT: The duplicate question doesn't actually answer my question. As the properties may not be in the order of priority. Hence, the first one that is looped through may be a lower priority than the highest one set.
For instance:
public class MyClass
{
public string MiddlePriority { get; set; }
public string HighPriority { get; set; }
}
EDIT: Thanks for the help everyone. As mjwills and I have discussed in the comments, The accepted answer would suit my needs as I have only around 6 properties in my class. But, if there were more, the duplicate answer is probably the best way to go.
Normally you can do something like this with the coalesce operator:
var highest = high ?? medium ?? low;
But it seems you want to treat "null" and "empty string" the same. So write a function that converts empty strings to nulls:
Func<string,string> func = s => s == "" ? null : s;
Then coalesce over that:
var highest = func(HighestPriority) ?? func(MediumPriority) ?? func(LowPriority);
I recommend this over using attributes and reflection. Yes you'll have to modify the code when you add a new property, but you're already modifying the code to add a property itself-- there is little point is making only half the solution automatic. While using a "flexible" solution and Reflection is a common temptation, in my experience it is usually counterproductive in the long term.
If you are married to the idea of scaling and adsorbing more and more properties automatically, I suggest using a List or Dictionary and using something like First().
I would go with John Wus answer and use coalesce operator, but there are other possiblities to get yourself a null instead of an empty string:
Create a extensionmethods class and extend the 'string' class:
public static class ExtensionMethod
{
public static string ConvertEmptyToNull(this string str)
{
return string.IsNullOrEmpty(str) ? null : str;
}
}
Than use coalesce operator:
var highest = HighestPriority.ConvertEmptyToNull() ?? MediumPriority.ConvertEmptyToNull() ?? LowPriority.ConvertEmptyToNull();
But in your case i would rather implement the getter of your properties since you have private fields for your properties.
private string highestPriority;
public string HighestPriority
{
get
{
return string.IsNullOrEmpty(highestPriority) ? null : highestPriority;
}
set
{
highestPriority = value;
HighestSetProperty = Priority.HighestPriority;
}
}
Now your coalesce chain will look cleaner:
var highest = HighestPriority ?? MediumPriority ?? LowPriority;
I get an error when I try to cast a query. This is the code of the query:
var query = (from article in db.V_CLIENT_PRIX
where article.CLIENT == Current_Client_Id
select new
{
ID = article.ID,
ARTICLE = article.Article,
REFERENCE = article.Reference,
REMISE = article.Remise,
PRIXVHT = article.PrixVHT,
CLIENT = article.CLIENT,
}
);
And I cast it like this:
ConventionList articlelistconvention = new ConventionList();
articlelistconvention = (ConventionList)query;
This is the code of my model:ConventionList
public class Commandelist
{
public string ARTICLE { get; set; }
public string CIN { get; set; }
public decimal STOCK { get; set; }
public string REFERENCE { get; set; }
public decimal PRIXVHT { get; set; }
public string IMAGE { get; set; }
public double QUANTITE { get; set; }
}
Can someone help me fix it?
You might be coming from a language with duck typing, like Javascript; however, in C# this is not possible. You can typically only cast objects if the interfaces and/or inheritance allows you to do so. The dynamic object you create in your Linq query will not share ancestry with the object you're trying to cast to.
In your specific code example though there is a quick fix:
var query = (
from article in db.V_CLIENT_PRIX
where article.CLIENT == Current_Client_Id
select new ConventionList // < --- change here!!
{
ID = article.ID,
ARTICLE = article.Article,
REFERENCE = article.Reference,
REMISE = article.Remise,
PRIXVHT = article.PrixVHT,
CLIENT = article.CLIENT,
});
However, getting this to work exactly for your scenario might require some tweaking, as your question is ambiguous about the difference / overlap between the dynamic object, the ConventionList class, and the CommandeList class.
You need to specify your type in the SELECT.
You can't cast anonymous types to declared types
You can't cast unrelated types to each other (command / convention) unless you just slopely pasted the wrong code for us to look at / figure out)
You can't cast List<T> of one type to another type, IEnemurable could work if the generics were related because of covariance.
Updated code with an explicit type in the constructor instead of an anonymous object, again I think you meant Convention but if not change it to the type you need.
var query = (
from article in db.V_CLIENT_PRIX
where article.CLIENT == Current_Client_Id
select new Convention()
{
ID = article.ID,
ARTICLE = article.Article,
REFERENCE = article.Reference,
REMISE = article.Remise,
PRIXVHT = article.PrixVHT,
CLIENT = article.CLIENT,
});
Ok, so here's an enum, right?
public enum BrandSafe : short
{
Yes = 1,
No = -1,
Unknown = 0
}
Underlying datatype of short, OK, so far so good.
Here is a table:
Now, here is a DTO class:
public class VurlRow
{
public long VurlRMXID { get; set; }
public string VurlString { get; set; }
public Enums.BrandSafe BrandSafe { get; set; }
}
Finally, here is a linq method:
List<VurlRow> vurls = (from vurl in m_Context.Vurls
select new VurlRow()
{
BrandSafe = (Enums.BrandSafe)vurl.BrandSafe,
VurlRMXID = vurl.VurlRMXID,
VurlString = vurl.VurlString
}).ToList();
I've also tried (Enums.BrandSafe)Enum.ToObject(typeof(Enums.BrandSafe), vurl.BrandSafe) to produce the Enum. When I remove the line BrandSafe = (Enums.BrandSafe)vurl.BrandSafe, the call works, but with the line I get a InvalidCast exception.
"Specified cast is not valid."
Seems like it should be totally valid to me, but what do I know, not enough about enums and linq apparently, can anyone here help?
BrandSafe is tinyint in the database; tinyint maps to byte, not short. That's the problem. Make it:
public enum BrandSafe : byte
{
Yes = 1,
No = -1, // <====== see below
Unknown = 0
}
(short would map to smallint)
However!!!! Note that -1 is not really a legal value for either of byte/tinyint - it will be 255 or an OverflowException in .NET (depending on whether it is a checked or unchecked context), and an arithmetic-overflow (error 220) at the database.
I do, however, wonder whether bool? (in C#) and bit null (TSQL) would be a better match.
I see some code will return the default value, so I am wondering for a user defined class, how will the compiler define its default value?
To chime in with the rest, it will be null, but I should also add that you can get the default value of any type, using default
default(MyClass) // null
default(int) // 0
It can be especially useful when working with generics; you might want to return default(T), if your return type is T and you don't want to assume that it's nullable.
The default value for class is a null
Note: A DefaultValueAttribute will not cause a member to be automatically initialized with the attribute's value. You must set the initial value in your code.
You can decorate your properties with the DefaultValueAttribute.
private bool myVal = false;
[DefaultValue(false)]
public bool MyProperty
{
get
{
return myVal;
}
set
{
myVal = value;
}
}
I know this doesn't answer your question, just wanted to add this as relevant information.
For more info see http://msdn.microsoft.com/en-us/library/system.componentmodel.defaultvalueattribute.aspx
The default value for classes is null. For structures, the default value is the same as you get when you instantiate the default parameterless constructor of the structure (which can't be overriden by the way). The same rule is applied recursively to all the fields contained inside the class or structure.
I would make this "default" class instance a field rather than property, like how System.String.Empty looks:
public class Person
{
public string Name { get; set; }
public string Address { get; set; }
public static readonly Person Default = new Person()
{
Name = "Some Name",
Address = "Some Address"
};
}
...
public static void Main(string[] args)
{
string address = String.Empty;
Person person = Person.Default;
//the rest of your code
}
If you are wondering why there isn't a language feature that allows you to somehow define a non-null default value for a class, remember that a class is a "reference type". A reference type is a reference to allocated memory, or in other words, anything except null is a constructed instance of that object which required memory to be allocated. So now thinking about how to integrate the "default" keyword into .NET so that it works for classes, imagine two implementations that could be considered:
You can define a static instance that is marked as the default. Maybe "default" becomes like an access modifier (e.g. public default readonly etc). This could work, maybe. But is it really a worthy language feature? At least this way every "default" would point to the same static instance of memory.
What if the default constructor were called every time you used the default keyword on a class? This would be terrible because two default values could possibly be unequal to each other if you didn't override Equals to not compare references, and also terrible because of the memory management and memory allocation performance hit, and side affects from the constructor.
So in summary I think it is a language feature that we really don't want. And default(MyClass) will always == null.
If it is a reference type, the default value will be null, if it is a value type, then it depends.
Assert.IsTrue(default(MyClass) == null);
For reference types or nullable value types the default will be null:
Person person = default; // = null
IEnumerable<Person> people = default; // = null
int? value = default; // = null
For value types, it depends on which value type it is:
int value = default; // = 0
DateTime dateTime = default; // = 1/1/0001 12:00:00 AM
Guid id = default; // = 00000000-0000-0000-0000-000000000000
Saving some other ppl's time, hopefully.
Obvious option nowadays (for which I still had to google a bit, as landed on this topic first) is to write an extention, that helps you to initialize a class, regardless of it's own complications (like constructor getters/setters, which prevent simple default value direct assignition).
Modifying previous answer a bit:
public class Person
{
public string Name { get; set; }
public string Address { get; set; }
public static readonly Person Default = new Person()
{
Name = "Some Name",
Address = "Some Address"
};
}
=>
public class Person
{
public string Name { get; set; }
public string Address { get; set; }
}
public static class PersonExtentions
{
public static Person withDefaults(this Person obj) {
obj.Name = "John Doe";
return obj;
}
}
And then
Person x = new Person.withDefaults();
I do not understand why there is Control.padding.all which is int and according to hint there is set as well as get but I cannot set it (Control.Padding.All=5)? I would be grateful for explanation. Thanks!
Control.Margin = new Padding(5)
Here is a simple Implementation of this
public class ARAControl
{
public ARAPadding Padding { get; set; }
}
public struct ARAPadding
{
public int All { get; set; }
}
And if you use this you probably get this error
ARAControl control = new ARAControl();
control.Padding.All = 10;
It hapens because structure is a value type. By setting this property you first call get Method. Property Get will return a copy of Padding so it is a value type and C# will detect out mistake and prevent compiling