Can a generic be Nullable? - c#

I have the following class:
public class RangeFilter<T> : IFilter<T> where T : IConvertible, IComparable {
public T Maximum { get; private set; }
public T Minimum { get; private set; }
public RangeFilter(T maximum) {
Minimum = null;
Maximum = maximum;
}
}
T can be an Int, a Double, ... When I pass only the maximum value I need the Minimum to be null but when I do that I get the following error:
Cannot convert null to type parameter 'T' because it could be a non-nullable value type.
Consider using 'default(T)' instead.
The reason I do not want to use default(T) is because I need to check later if Minimum is defined and default(T) is a valid value for Minimum.

As long as T is not nullable you can not set the value to null what you can do is something like this ...
public class RangeFilter<T> : IFilter<T>
where T : struct, IConvertible, IComparable
{
public T? Maximum { get; private set; }
public T? Minimum { get; private set; }
public RangeFilter(T maximum)
{
Minimum = null;
Maximum = maximum;
}
}

The problem is clearly described by a compiler error, but you can't use Nullable<T> because it's completely unusable here (what if T is a reference type, or Nullable<U>?) Fortunately, you can try an alternative, which is Functional.Maybe. It works both for value types and reference types.

The class you are creating is nullable by nature, the type you pass might not be. You can either restrict the type you pass as T (doc) or change your assignment to support both scenarios.

You could make flags instead of using a magic value to let you know if Minimum was set or not something is set or not
public HasMinimum {get; private set;}
private T _min;
public T Minimum
{
get
{
if(!HasMinimum)
throw new InvalidOperationException("Minimum not set");
return _min;
}
private set
{
HasMinimum = true;
_min = value;
}
}
Then in your constructor just don't set the minimum property
public RangeFilter(T maximum)
{
Maximum = maximum;
}

int and double are not nullable types, so they must have a value assigned to them and that's why you are getting that error. Although, you can use T? or Nullable<T> as a work around:
int? t = null; // t is nullable, so it works
You also can use nested Nullable<T>.GetValueOrDefault which can be also useful in your case, if you have a default value for your Min or Max.

Related

Json Ignore when writing default in certain Type C#

Is it possible on System.Text.Json to conditionally ignore when default if it is a certain type?
Because I have this type
public struct Optional<T>
{
public bool HasValue { get; init; }
public T Value { get; init; }
public Optional(T value) =>
(HasValue, Value) = (true, value);
}
I can ignore it when default globally with JsonSerializerOptions.DefaultIgnoreCondition but this also means if I have a bool with false value or int with 0 value it will be ignored, and I only want to ignore when default if the type is specifically Optional<T>
Any suggestions?
Also, I don't want to use [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)], I know I can do that but I want to make it globally with that certain type

How to create a class property in c# that is set based on computed time value but which then can be modified by a user

Hope the question was clear.
I have a class structure in place and using it in an application already.
User would like to however change their total time keeping the calculated time intact. Calculated time is based on ComputeHours.
How do I introduce another property that will set its value based on ComputeHours for all existing data. Then if User changes this value, the new property should reflect this adjusted time.
public decimal TotalHours
{
get { return ComputeHours(); }
}
//Introducing new property
public decimal TotalAdjusted
{
???
}
It's important that I get the new property to set default to existsing property value, since the Grand Total time will then be based of this.
this is the typical pattern:
private decimal _totalAdjusted;
public ThisIsMyConstructor(){
_totalAdjusted = ComputeHours();
}
public decimal TotalAdjusted
{
set { _totalAdjusted = value; }
get { return _totalAdjusted ; }
}
since this isn't really doing anything special with _totalAdjusted, you can simplify it to this:
public ThisIsMyConstructor(){
TotalAdjusted = ComputeHours();
}
public decimal TotalAdjusted {get; set;}
If the result of ComputHours tends to change, and you want the default value to change with it, you can do this instead.
private decimal? _totalAdjusted == null;
public decimal TotalAdjusted
{
set { _totalAdjusted = value; }
get
{
return _totalAdjusted.HasValue ? _totalAdjusted.Value : ComputeHours();
}
}
Here's an explanation of some of the syntax there
the question mark on decimal? means that it's nullable.
HasValue is a property on a nullable object which is true when the nullable object is not null.
the Value property returns a non-nullable version of the nullable object.
The ? and : is the ternary operator. It essentially means if totalAdjusted.HasValue is true, then use _totalAdjusted.Value else use ComputeHours()
you can also just use the null coalescing operator to do the same thing.
return _totalAdjusted ?? ComputeHours();
the expression to the right of the ?? represents a default value in case _totalAdjusted is null

Why do I get the 'Operator '!=' can not be applied to operands of type Point and <null>' in this struct implementation

I don't really know why I get this error while trying to validate the input value in the Property code here:
using ConsoleApplication4.Interfaces;
public struct Vector:IComparable
{
private Point startingPoint;
private Point endPoint;
public Point StartingPoint
{
get
{
return new Point(startingPoint);
}
set
{
if(value != null)
this.startingPoint = value;
}
}
public Point EndingPoint
{
get
{
return new Point(this.endPoint);
}
set
{
if(value != null)
this.startingPoint = value;
}
}
The error that I get is on the lines where I have if(value!=null)
struct is a value type - it cannot be "null" like a class could be. You may use a Nullable<Point> (or Point?), however.
Point is a struct and hence can't be null.
You can use Point? which is syntactic sugar for System.Nullable<Point>. Read more about nullable types at http://msdn.microsoft.com/en-us/library/1t3y8s4s(v=vs.120).aspx
If you want to compare to the default value of Point (which is not the same as null), then you can use the default keyword:
if(value != default(Point))
A struct is a value type, not a reference type. This implies, that it can never be null, especially, that its default value is not null.
Easy rule of thumb: If you need new(), it can be null. (This is a bit simplicistic, but devs knowing, when this might be wrong, most often don't need a rule of thumb)
I don't know what you are trying to achieve with your class, but it seems what you can simply write:
public struct Vector: IComparable
{
public Point StartingPoint {get; set;}
public Point EndPoint {get; set;}
// implement IComparable
}
unless you intentionally want to create a copies of points (for whatever reason)

Why is a Nullable<T> not a valid Custom Attribute Parameter when T is?

If I have an enum like this
public enum Hungry
{
Somewhat,
Very,
CouldEatMySocks
}
and a custom attribute like this
public class HungerAttribute : Attribute
{
public Hungry HungerLevel { get; set; }
public Hungry? NullableHungerLevel { get; set; }
}
I can do this
[Hunger(HungerLevel = Hungry.CouldEatMySocks)]
public class Thing1
but I can't do this
[Hunger(NullableHungerLevel = Hungry.CouldEatMySocks)]
public class Thing2
It generates an error that says "'NullableHungerLevel' is not a valid named attribute argument because it is not a valid attribute parameter type".
Why is that not allowed? I understand that fundamentally it just isn't on the list of accepted types. The valid types seem to be primitives, enums, string, type, and one dimensional arrays of the preceding types.
Is this just an old rule that did not get updated when Nullable came along?
Hungry? is equal to Nullable<Hungry>, which in terms mean that
[Hunger(NullableHungerLevel = Hungry.CouldEatMySocks)]
is equal to
[Hunger(NullableHungerLevel = new Nullable<Hungry>(Hungry.CouldEatMySocks))]
Since you can only use constant values in named attribute arguments you will have to resort to Shimmy's solution.
To get around this create another initializer in your Attribute:
class Program
{
[Hunger()]
static void Main(string[] args)
{
}
public sealed class HungerAttribute : Attribute
{
public Hungry? HungerLevel { get; }
public bool IsNull => !_HungerLevel.HasValue;
public HungerAttribute()
{
}
//Or:
public HungerAttribute(Hungry level)
{
HungerLevel = level;
}
}
public enum Hungry { Somewhat, Very, CouldEatMySocks }
}
I understand that you're not going to use both properties.
Attributes may have as only parameters primitives, typeof expressions and array-creation expression.
Nullable is a struct.
Therefore it is not allowed there.
I suspect the assembly file format itself doesn't allow storage of complex types like structs in the place where attribute values are stored.
I don't know of any plans to change that. But I cannot explain why this restriction exist.
Instead of creating nullable enum, you can create default value for that enum. Enum pick default from 1st value, so set your enum like this
public enum Hungry
{
None,
Somewhat,
Very,
CouldEatMySocks
}
in your code you could do this to check for null
if(default(Hungry) == HungerLevel)//no value has been set

Best way to design a multi-type object

Let's say I have a data object, but this object can hold one of several types of data.
class Foo
{
int intFoo;
double doubleFoo;
string stringFoo;
}
Now, I want to create an accessor. Some way to get at this data. Obviously, I could create multiple accessors:
public int GetIntFoo();
public double GetDoubleFoo();
public string GetStringFoo();
Or I could create multiple properties
public int IntFoo { get; set; }
public double DoubleFoo { get; set; }
public string StringFoo { get; set; }
I don't that this is a very good design. It requires the client code to be more concerned about type than it should have to be. What's more, I really need only a single value for this class and the above would allow one of each type to be assigned at the same time. Not good.
One option is to use Generics.
class Foo<T>
{
public T TheFoo { get; set; }
}
However, this doesn't create a Foo, it creates a Foo<T>. A different type for each, so I can't really use them as the same type.
I could derive Foo<T> from FooBase, then treat all of them as FooBase's, but then i'm back in the problem of accessing the data.
A different Generics option is to use something like this:
class Foo
{
string stringRepresentationOfFoo;
public T GetFoo<T>() { return /* code to convert string to type */ }
}
OF course the problem is that any kind of T could be passed, and frankly, it's a bit busy.
I could also just box the values and return an object, but then there is no type safety.
Ideally, I want to treat all Foo's the same, but I want type safety so that if there isn't a StringFoo, I can't even compile a reference to a StringFoo.
Foo foo = new Foo("Foo");
string sFoo = foo.Value; // succeeds.
Foo foo = new Foo(0);
int iFoo = foo.Value; // succeeds
string sFoo = foo.Value; // compile error
Perhaps this isn't even possible.. and I'll have to make some compromises, but maybe i'm missing something.
Any ideas?
EDIT:
Ok, so as daniel points out, the compile time checking of a runtime type is not practical.
What is my best option for doing what I want to do here? Namely, Treat all Foo's the same, but still have a relatively sane access mechanism?
EDIT2:
I don't want to convert the value to different types. I want to return the correct type for the value. That is, if it's a double, I don't want to return an int.
How about passing in the variable as a parameter to the get? Like this:
int i = foo.get(i);
Then in your class, you'd have something like:
public int get(int p) {
if(this.type != INTEGER) throw new RuntimeException("Data type mismatch");
return this.intVal;
}
public float get(float p) {
if(this.type != FLOAT) throw new RuntimeException("Data type mismatch");
return this.floatVal;
}
This sort of turns the type checking inside-out: instead of checking what type foo holds, you have foo check what type you want. If it can give you that type, it does, or else it throws a runtime exception.
I don't think this could work (giving you the compiler error you want)
What would you want this to do:
Foo bar = (new Random()).Next(2) == 0 ? new Foo("bar") : new Foo(1);
int baz = bar.Value;
Is that a compiler error?
I think "treat them all the same" (at least the way you've described it) and "compile time error" are going to be mutually exclusive.
In any case, I think the "best way" is going to be a compromise between generics and inheritance. You can define a Foo<T> that is a subclass of Foo; then you can still have collections of Foo.
abstract public class Foo
{
// Common implementation
abstract public object ObjectValue { get; }
}
public class Foo<T> : Foo
{
public Foo(T initialValue)
{
Value = initialValue;
}
public T Value { get; set; }
public object ObjectValue
{
get { return Value; }
}
}
Many systems use a helper methods to return the alternate types just as the .net frameworks base object has the ToString() method
Choose which is the best base type for each of your object and provide To methods for other cases
e.g.
class Foo{
public Int32 Value { get; set; }
public Byte ToByte() { return Convert.ToByte(Value); }
public Double ToDouble() { return (Double)Value; }
public new String ToString() { return Value.ToString("#,###"); }
}
One thing is to store any type in your internal state of the class, and another is to expose it externally. When you write a class, you are actually declaring a contract for its behavior. The way you write it will influence greatly how client code will look like when using the class.
For example, by implementing the IConvertible interface you state that your type can be converted to any CLR type as an equivalent value.
I have also seen implementations where a Value class was used to store results of calculations, results that could represent either a string, double, int or boolean. But, the problem was that client code had to check a Value.Type property of an enum {String, Integer, Double, Boolean} and then either cast the Value.Value property (which was exposed externally by the Value class as an Object type) or use the specific ValueString, ValueDouble, ValueInt, ValueBoolean getters.
Why not just use string, double and int?
After info about collection: What about using object? You will have to check for types and such afterwards anyways. And to help you with that you can use the is and as operators. And the Enumerable.Cast Method, or even better, the Enumerable.OfType Method.
Actually, what is the purpose of this class? The biggest problem seems to be design breaking at least SRP (single responsibility principle).
Nonetheless, if I'm reading it correctly, you'd like to store some value in the container, pass the container to client and type-safely retrieve the value.
With this approach, you can use your proposal, i.e.
namespace Project1 {
public class Class1 {
static int Main(string[] args) {
Foo a = new Foo();
a.SetValue(4);
Console.WriteLine(a.GetValue<int>());
Foo b = new Foo();
a.SetValue("String");
Console.WriteLine(a.GetValue<string>());
Console.ReadLine();
return 0;
}
}
class Foo {
private object value; // watch out for boxing here!
public void SetValue(object value) {
this.value = value;
}
public T GetValue<T>() {
object val = this.value;
if (val == null) { return default(T); } // or throw if you prefer
try {
return (T)val;
}
catch (Exception) {
return default(T);
// cast failed, return default(T) or throw
}
}
}
}
However, in that case why not simply pass data as object and cast by yourself?
Depending on your needs, you may also try "PHP in C#":
namespace Project1 {
public class Class1 {
static int Main(string[] args) {
MyInt a = 1;
MyInt b = "2";
Console.WriteLine(a + b); // writes 3
Console.ReadLine();
return 0;
}
}
class MyInt {
private int value;
public static implicit operator int(MyInt container) {
return container.value;
}
public static implicit operator MyInt(int value) {
MyInt myInt = new MyInt();
myInt.value = value;
return myInt ;
}
public static implicit operator MyInt(string stringedInt) {
MyInt myInt = new MyInt();
myInt.value = int.Parse(stringedInt);
return myInt;
}
}
}
I'm sorry, I just don't buy your premise. If the data all have the same purpose, then they should all have the same type. Consider a class that's meant to hold the current temperature, as returned by one of several web services. All the services return the temperature in Centigrade. But one returns as an int, one returns as a double, and one returns it as a string.
It's not three different types - it's one type - double. You would simply need to convert the non-double returns into double, which is what the temperature is (or maybe float).
In general, if you have multiple representations of one thing, then it's still one thing, not multiple things. Convert the multiple representations into one.

Categories

Resources