I am trying to make a Money datatype (like int, string) in C#. However I can't seem to work out how to use it without the new Modifier. The class cannot be static as it has to be assigned to. I figured there must be a way, here is the code I have for the class, I may be doing this completely wrong.
public class Money {
private float _raw;
public float Raw {
get { return _raw; }
set { _raw = value; }
}
public string Pound {
get { return "£" + string.Format("{0:0.00}", _raw); }
}
}
Then I have the class I am calling it in and would like to just use:
private Money _money;
Instead of:
private Money _money = new Money();
Sorry if this is a stupid question but I couldn't find anything online nor could I figure it out myself.
You'll have to new it up somewhere. If you don't want to do it in the member declaration, then do it in the class constructor:
public MyClass()
{
_money = new Money();
}
An alternative solution involves using a factory method of some kind.
public class Money {
private float _raw;
public float Raw {
get { return _raw; }
set { _raw = value; }
}
public string Pound {
get { return "£" + string.Format("{0:0.00}", _raw); }
}
public static Money From(float val)
{
Money x = new Money();
x.Raw = val;
return x;
}
}
usage:
Money m = Money.From(9.95);
Using impilicit operator will allow you to set it like primitive data type.
http://haacked.com/archive/2012/09/30/primitive-obsession-custom-string-types-and-self-referencing-generic-constraints.aspx
public class Money
{
private float _raw;
public float Raw
{
get { return _raw; }
set { _raw = value; }
}
public string Pound
{
get { return "£" + string.Format("{0:0.00}", _raw); }
}
public static implicit operator Money(float value)
{
return new Money(){Raw = value};
}
}
Then you can use it like this.
Money m = 12;
Console.Write(m.Raw);
If you do not want to use property Raw to assign value you can make a operator overload, something like that:
public static implicit operator Money(Double value)
{
var money = new Money();
money.Raw = value;
return money;
}
And then in the calling code:
Money money = 10d;
But IMHO, i don't see any advantage in doing that, if you really need a muttable type, there should be no problem calling 'new' to instantiate it.
Adding a private constructor would prevent outsiders from "newing up" an instance... but then you also need to write a factory method or something to create it (in your class so that it has access to the private constructor). Otherwise your class is pretty useless!
That said, maybe if we knew why you didn't want to be able to "new up" an instance, we might be able to provide some tips.
Related
I have a property where I want to convert the values systematically and I have a very large set of properties, so rather than have the following:
class myClass
{
private Double _Length;
public Double Length { get { return convert(_Length); } set { _Length = convertBack(value); }}
private Double _Height;
public Double Height{ get { return convert(_Height); } set { _Height= convertBack(value); }}
private Double _Width;
public Double Width{ get { return convert(_Width); } set { _Width= convertBack(value); }}
...
Double convert(Double base_value) { do work to return converted_value; }
Double unconvert(Double converted_value) { to work to return base_value; }
}
I would like to do something like this to reduce code pollution and redundancy
class myBaseClass
{
class DoublePropertyConverter extends Property
{
public Double get { return convert(this); }
public Double set { this = unconvert(value); }
}
Double convert(Double base_value) { do work to return converted_value; }
Double unconvert(Double converted_value) { to work to return base_value; }
}
class myClass : public myBaseClass
{
[DoublePropertyConverter]
public Double Length { get; set;}
[DoublePropertyConverter]
public Double Height{ get; set;}
[DoublePropertyConverter]
public Double Width{ get; set;}
...
}
Is this, or something like it, at all possible?
There's no way to "extend a property" in the way you're describing, no.
But it's easy enough to create a new type which represents conversions from and two some other value. Types like DateTime and TimeSpan are all just wrappers around a long that handle conversions to different semantic values for you, for example. Honestly it sounds like you should have a new type, because you've got a value that a consumer wants to treat in one way, but that is actually represented in memory as something else, and types are great at accomplishing just that in many situations that goes beyond the scope of getting and setting property values.
public class Foo
{
public Foo(double value)
{
underlyingValue = FromDouble(value);
}
private readonly object underlyingValue;
public double Value => ToDouble(underlyingValue);
public static implicit operator double(Foo foo) => ToDouble(foo.underlyingValue);
public static implicit operator Foo(double value) => new Foo(value);
private static double ToDouble(object underlyingVvalue)
{
throw new NotImplementedException();
}
private static object FromDouble(double value)
{
throw new NotImplementedException();
}
}
The underlying field in the type can be whatever you want that you're converting to/from, and you can then define your conversion logic in just one place.
Suppose I have a C# class that has multiple properties that all look like this:
private bool _var1Dirty = true;
private Double? _var1;
public Double? Var1
{
get
{
if (_var1Dirty)
{
_var1 = Method_Var1();
_var1Dirty = false;
}
return _var1;
}
}
And the only differences between each of these properties would be:
The type of return var (in this case Double?, but could just as easily be int, string, etc)
The method call - Method_Var1() (Each property would have a different one)
Is there any way I could write this as a custom class?
Something along the lines of:
public class Prop
{
public delegate T Func();
private bool _dirty = true;
private T _val;
public T Val
{
get
{
if (_dirty)
{
_val = Func;
_dirty = false;
}
return _val;
}
}
}
And then I could pass into it the:
Return type T
Method Func
(PS - I know this won't compile / is dead wrong, but I wanted to give an idea of what I'm looking for)
Any help / guidance would be really appreciated.
Thanks!!!
You're close. You can do something along the lines of this:
public class Dirty<T>
{
public Dirty(Func<T> valueFactory)
{
this.valueFactory = valueFactory;
dirty = true;
}
private Func<T> valueFactory;
private bool dirty;
private T value;
public T Value
{
get
{
if (dirty)
{
value = valueFactory();
dirty = false;
}
return value;
}
}
}
And you consume it like this:
Dirty<double?> dirtyDouble = new Dirty<double?>(() => SomethingThatReturnsADouble());
double? value = dirtyDouble.Value;
I'm not sure what the dirty checking actually does, but if you need someone more complicated than a bool you can always turn it into some Func<T> the checks for dirtiness.
Edit:
Given #mikez comment and your answer, you can save yourself the creation of the Dirty<T> class by using the built in Lazy<T>, which also guarantess thread safety:
public class F
{
private Lazy<double?> lazyDouble = new Lazy<double?>(() =>
MethodThatReturnsNullableDouble(), true);
public double? Value
{
get
{
return lazyDouble.Value;
}
}
}
Is it possible to set or override the default state for a structure?
As an example I have an
enum something{a,b,c,d,e};
and a structure that links 2 values for that enum
struct SomethingData
{
something type;
int Value;
double Multipler;
SomethingData(something enumVal, int intVal, double DblVal) {...}
}
But can I specify that the default state is
SomethingData(something.c,0,1);
Struct constructors are similar to
class constructors, except for the
following differences:
Structs cannot contain explicit
parameterless constructors. Struct
members are automatically initialized
to their default values. A struct
cannot have an initializer in the
form: base (argument-list).
http://msdn.microsoft.com/en-us/library/aa288208(v=vs.71).aspx
So, short answer, no you can't override the default constructor (every struct has a parameterless constructor and you can't hide it or override it)...
You can't. Structs always have a default constructor that sets every member to its default value (null for reference types, 0 for numeric types, false for bools, etc.) This behavior cannot be changed.
You can't override the default (parameterless) constructor for a struct. You can only add new constructors, which take parameters.
http://csharp.2000things.com/2010/10/03/108-defining-a-constructor-for-a-struct/
Creating a class object will cause all of the instance fields to come into existence before anything--even the class constructor--can access it, and allocating an array will cause all of its elements to exist before anything can access the array. Both of these actions will cause all of the memory allocated to those fields or elements to be zeroed out without regard for the data types to be stored therein.
When a class-type storage location comes into existence, it will initially hold a null reference. When a structure-type storage location comes into existence, all of its fields (and any fields of structures within it) will do so simultaneously. Unlike class object instances which can only come into existence by using a constructor, structure-type storage locations are brought into existence without using any of the structure's own code. Consequently, the structure's definition will have no say in what should happen when "instances" [i.e. struct-type storage locations] come into existence.
A struct is, fundamentally, a collection of fields bound together with duct tape. If a struct is supposed to behave like something else, it should typically make its fields private and pretend to be immutable [even though struct assignment actually mutates the destination struct by overwriting all its fields with the corresponding values from the source, and the struct definition gets no say in the matter]. If, however, a struct is supposed to encapsulate a fixed set of related but independent values (e.g. the coordinates of a point), which may independently accommodate any combination of values which are legal for their respective types, a struct should simply expose its fields publicly. Some people may whine about "mutable structs are evil", but the evils only apply when invoking self-mutating methods on a struct. Structs which expose their state as fields behave like collections of variables stuck together with duct tape. If what one needs is a collection of variables stuck together with duct tape, trying to make a struct pretend to be immutable will simply make it harder to program with.
There is a workaround to make this happen by using custom Property getters. Observe:
public struct Foostruct
{
private int? _x;
private int? _y;
public int X
{
get { return _x ?? 20; } // replace 20 with desired default value
set { _x = value; }
}
public int Y
{
get { return _y ?? 10; } // replace 10 with desired default value
set { _y = value; }
}
}
This will only work for value types (which can be wrapped with nullable) but you could potentially do something similar for reference types by wrapping them in a generic class like below:
public class Wrapper<TValue>
{
public TValue Value { get; set; }
}
public struct Foostruct
{
private Wrapper<Tick> _tick;
public Tick Tick
{
get { return _tick == null ? new Tick(20) : _tick.Value; }
set { _tick = new Wrapper<Tick> { Value = value }; }
}
}
Somewhat related: I've often wanted to use the new object initializer syntax with an immutable value type. However, given the nature of a typical immutable value type implementation, there is no way to utilize that syntax, since the properties are read-only.
I've come up with this approach; In my opinion this still satisfies the immutability of the value type, but allows the code that is responsible for instantiating the value type greater control over the initialization of the internal data.
struct ImmutableValueType
{
private int _ID;
private string _Name;
public int ID
{
get { return _ID; }
}
public string Name
{
get { return _Name; }
}
// Infuser struct defined within the ImmutableValueType struct so that it has access to private fields
public struct Infuser
{
private ImmutableValueType _Item;
// write-only properties provide the complement to the read-only properties of the immutable value type
public int ID
{
set { _Item._ID = value; }
}
public string Name
{
set { _Item._Name = value; }
}
public ImmutableValueType Produce()
{
return this._Item;
}
public void Reset(ImmutableValueType item)
{
this._Item = item;
}
public void Reset()
{
this._Item = new ImmutableValueType();
}
public static implicit operator ImmutableValueType(Infuser infuser)
{
return infuser.Produce();
}
}
}
class Program
{
static void Main(string[] args)
{
// use of object initializer syntax made possible by the Infuser type
var item = new ImmutableValueType.Infuser
{
ID = 123,
Name = "ABC",
}.Produce();
Console.WriteLine("ID={0}, Name={1}", item.ID, item.Name);
}
}
Each time you get/set property you need to set default value call InitDefaultValues() method
private string _numberDecimalSeparator;
public string NumberDecimalSeparator
{
get
{
InitDefaultValues();
return _numberDecimalSeparator;
}
set
{
InitDefaultValues();
_numberDecimalSeparator = value;
}
}
...
private void InitDefaultValues()
{
if (!_inited)
{
_inited = false;
var ci = CultureInfo.CurrentCulture;
_numberDecimalSeparator = ci.With(x => x.NumberFormat).Return(x => x.NumberDecimalSeparator, ".");
...
}
}
Kinda dumb, but works
public readonly static float default_value = 1;
public struct YourStruct{
public float yourValue{
get {
return _yourValue + default_value;
}
set {
_yourValue= value - default_value;
}
}
public float _yourValue;
}
My solution. It works as well.
public struct DisplayOptions
{
public bool isUpon;
public bool screenFade;
public static DisplayOptions Build()
{
// Return default value
return new DisplayOptions(true, true);
}
DisplayOptions(bool isUpon, bool screenFade)
{
this.isUpon = isUpon;
this.screenFade = screenFade;
}
public DisplayOptions SetUpon(bool upon)
{
this.isUpon = upon;
return this;
}
public DisplayOptions SetScreenFade(bool screenFade)
{
this.screenFade = screenFade;
return this;
}
}
Use default value
// Use default
UIMaster.Instance.StartScreen("Screen 2", DisplayOptions.Build());
// Use custome
UIMaster.Instance.StartScreen("Screen 2", DisplayOptions.Build().SetScreenFade(false));
UIMaster.Instance.StartScreen("Screen 2", DisplayOptions.Build().SetUpon(false));
this should work
public struct MyStruct
{
private string myName;
private int? myNumber;
private bool? myBoolean;
private MyRefType myType;
public string MyName
{
get { return myName ?? "Default name"; }
set { myName= value; }
}
public int MyNumber
{
get { return myNumber ?? 42; }
set { myNumber = value; }
}
public bool MyBoolean
{
get { return myBoolean ?? true; }
set { myBoolean = value; }
}
public MyRefType MyType
{
get { return myType ?? new MyRefType(); }
set { myType = value; }
}
//optional
public MyStruct(string myName = "Default name", int myNumber = 42, bool myBoolean = true)
{
this.myType = new MyRefType();
this.myName = myName;
this.myNumber = myNumber;
this.myBoolean = myBoolean;
}
}
[TestClass]
public class MyStructTest
{
[TestMethod]
public void TestMyStruct()
{
var myStruct = default(MyStruct);
Assert.AreEqual("Default name", myStruct.MyName);
Assert.AreEqual(42, myStruct.MyNumber);
Assert.AreEqual(true, myStruct.MyBoolean);
Assert.IsNotNull(myStruct.MyType);
}
}
This may work...
public struct MyStruct
{
private bool _name;
public string myName
{
get { return (_name ? myName : "Default name"); }
set { _name = true; myName = value; }
}
private bool _num;
public int myNumber
{
get { return (_num ? myNumber : 42); }
set { _num = true; myNumber = value; }
}
private bool _bool;
public bool myBoolean
{
get { return (_bool ? myBoolean : true); }
set { _bool = true; myBoolean = value; }
}
private bool _type;
public MyRefType myType
{
get { return _type ? myType : new MyRefType(); }
set { _type = true; myType = value; }
}
}
Nevermind StackOverflowException
There is a workaround
public struct MyStruct
{
public MyStruct(int h = 1, int l = 1)
{
high = h;
low = l;
}
public int high;
public int low;
}
in a file I defined a public struct
public struct mystruct
{
public Double struct1;
public Decimal struct2;
}
In another I tried to do this:
class Test
{
mystruct my_va;
public mystruct my_va
{
get { return my_va; }
set { my_va = value; }
}
public Test()
{
my_va.struct1 = 10;
}
}
Intellisense recognizes My_va.struct1 but compiler says
Error 1 Cannot modify the return value
of 'TEST.mystruct' because it is not a
variable
How to correct the syntax ?
Yup, it's absolutely right. You see, when you fetch My_va, you're fetching a value - a copy of the current value of my_va. Changing that value would have no benefit, because you'd be immediately discarding the copy. The compiler is stopping you from writing code which doesn't do what it looks like it does.
In general, avoid mutable structs. They're evil. In this case, you could (for example) change mystruct to be immutable, but with a method like this:
public mystruct WithStruct1(double newValue)
{
return new mystruct(newValue, struct2);
}
then change your constructor code to:
My_va = My_va.WithStruct1(10);
... although in this case it's far more likely (given that you're in a constructor) that you should be writing:
My_va = new mystruct(10, 0);
Not only should structs be immutable, they should be pretty rare in most codebases, IMO. Other than for Noda Time, I've hardly ever written my own custom values types.
Finally, please learn the .NET naming conventions and try to follow them, even for sample code :)
It is highly recommended to avoid mutable structs. They exhibit all sorts of surprising behaviour.
Solution: Make your struct immutable.
public struct MyStruct
{
public readonly double Value1;
public readonly decimal Value2;
public MyStruct(double value1, decimal value2)
{
this.Value1 = value1;
this.Value2 = value2;
}
}
Usage:
class Test
{
private MyStruct myStruct;
public Test()
{
myStruct = new MyStruct(10, 42);
}
public MyStruct MyStruct
{
get { return myStruct; }
set { myStruct = value; }
}
}
I work with a list of structs, and solved this in a different way.
struct Pixel
{ Public int X;
Public int C;
}
List<Pixel> PixelList = new List<Pixel>
TempPixel = new Pixel();
Now when i want to set a value i code like this :
TempPixel = PixelList[i];
TempPixel.X= 23; // set some value
PixelList[i] = TempPixel
The code looks a bit strange perhaps, but it resolves the issue .
It solves the problem that a struct cannot be directly assigned a single value, but can be a copy of a similar type.
solving error CS1612:
https://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k%28CS1612%29;k%28TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERSION%3dV2.0%22%29;k%28DevLang-CSHARP%29&rd=true
Simplest fix: Change the struct to a class.
Unfortunately this error can be incorrectly generated when assigning to a property (i.e. invoking a property setter). An immutable struct can still have a valid property setter, as long as the property setter doesn't actually assign to any fields in the struct. For example,
public struct Relay
{
public Relay(Func<string> getText, Action<string> setText)
{
this.GetText = getText;
this.SetText = setText;
}
private readonly Func<string> GetText;
private readonly Action<string> SetText;
public string Text {
get { return this.GetText(); }
set { this.SetText(value); }
}
}
class Example
{
private Relay Relay {
get { return new Relay(() => this.text, t => { this.text = t; }); }
}
private string text;
public Method()
{
var r = new Relay();
r.Text = "hello"; // not a compile error (although there is a null reference)
// Inappropriately generates a compiler error
this.Relay.Text = "hello";
r = this.Relay;
r.Text = "hello"; // OK
}
}
Worth noting, that you can overcome this behavior by:
Implementing interface by struct: Struct : IStruct
Declare struct as field: Struct strExplicitly;
Example:
public interface IStruct
{
int Age { get; set; }
}
public struct Struct : IStruct
{
public int Age { get; set; }
}
public class Test
{
IStruct strInterface { get; set; }
Struct strExplicitly;
public Test()
{
strInterface = new Struct();
strExplicitly = new Struct();
}
public void ChangeAge()
{
strInterface.Age = 2;
strExplicitly.Age = 2;
}
}
Simple question, hopefully a simple answer:
I'd like to do the following:
private DateTime m_internalDateTime;
public var DateTimeProperty
{
get { return m_internalDateTime.ToString(); } // Return a string
set { m_internalDateTime = value; } // here value is of type DateTime
}
The above is just an example of what I'm trying to do. I'd like to have a public accessor to an internal variable of type x. I want the get that variable as a string, but set it using something of type x.
Is this possible?
--edit--
I just realized I could do something like:
private DateTime m_internalDateTime;
public object DateTimeProperty
{
get { return m_internalDateTime.ToString(); } // Return a string
set { m_internalDateTime = (DateTime)value; } // here value is of type DateTime
}
But then, let say I use type y instead of a "string" as my 'get' type. If I want to use "DateTimeProperty" else where in my code, I'd have to cast it.
No. You can obviously add the .ToString() in the calling code, but you can't do what you propose without different names like this:
private DateTime m_internalDateTime;
public DateTime SetDateTime { set { m_internalDateTime = value; } }
public string GetDateTime { get { return m_internalDateTime.ToString(); } }
Or, even better to use methods instead of properties (as noted in the comments):
private DateTime m_internalDateTime;
public void SetDateTime(DateTime dateTime) { m_internalDateTime = dateTime; }
public string GetDateTime() { return m_internalDateTime.ToString(); }
Keep in mind that var is for implicitly, compile-time typed variables, not dynamic variables.
Definitely do not do what you noted in your edit. It introduced a break in convention, possible performance implications (albeit slight), and significant localization problems.
As a property, no this is not possible. You could make Get and Set methods that are of different types, but for a property the types must be the same.
EDIT:
While:
private DateTime m_internalDateTime;
public object DateTimeProperty
{
get { return m_internalDateTime.ToString(); } // Return a string
set { m_internalDateTime = (DateTime)value; } // here value is of type DateTime
}
is syntactically correct, will compile and allows you to accept DateTime as input and return a string, this would not be a good plan. It works, but it makes you and anyone accessing this code, perform unneeded validation. Additionally, it is vulnerable to another developer in the future, not knowing, or realizing the implicit rules, for which you have lost compile time safety. Additionally, its hardly any more code to create either two properties, or two methods that accomplish the same goal, in a strongly typed manner.
Personally, I would recommend using two methods (see Jeff Yates comment for a good explanation as to why).
private DateTime m_internalDateTime;
public string GetDateTime()
{
return m_internalDateTime.ToString();
}
public void SetDateTime(DateTime dateTime)
{
m_internalDateTime = dateTime;
}
Not that way, but you can certainly have a second property that accesses the m_internalDateTime field.
public string DateTimeString
{
get { return m_internalDateTime.ToString(); }
}
Maybe that helps
public class TDecimal
{
private decimal? m_value;
public bool HasValue { get { return m_value.HasValue; } }
public decimal Value { get { return m_value.Value; } }
public static implicit operator TDecimal(string a_value)
{
decimal d;
if (decimal.TryParse(a_value, out d))
{
return new TDecimal() {m_value = d};
}
return new TDecimal() {m_value = null};
}
public static implicit operator decimal(TDecimal a_value)
{
if(a_value.HasValue)
{
return a_value.Value;
}
throw new ArgumentNullException("a_value");
}
}
public class A
{
public TDecimal Prop { get; set; }
}
A a = new A();
a.Prop = "123";
if (a.Prop.HasValue)
{
decimal d = a.Prop;
}
Simple answer no, to your outside code your property will behave the exact way that a field would, you can't have a property having different set/get types just as you couldn't have a filed be set with a type and when you request it's value get a different type back.
how about:
private DateTime intDT;
public string DateTimeProperty
{
get { return intDT.ToString(); } // Return a string
set
{
DateTime dt;
if (DateTime.TryParse(value, out dt))
intDT = dt;
else throw new ArgumentException(string.Format(
"{0} cannot be converted to a DateTime.", value);
}
}