C# enum conversion, cleanest way - c#

Background
Having a delphi background I am used to fixing lots of thgings using constants and const arrays et all. Also Delphi allpws to have type conversions on enums using helper classes.
Now take a look at these enums from C#
public enum DateInterval { Off, Day, Month, Year };
public enum TimeInterval { Off, MilliSecond, Second, Minute, Hour };
public enum DateTimeInterval { Off, MilliSecond, Second, Minute, Hour, Day, Month, Year };
As you can see, there can be a logical conversion between thse enums, and I have managed to accomplish this using:
public static class DateIntervalHelper
{
public static DateTimeInterval ToDateTimeInterval(this TimeInterval aInterval)
{
switch (aInterval)
{
case TimeInterval.MilliSecond:
return DateTimeInterval.MilliSecond;
case TimeInterval.Second:
return DateTimeInterval.Second;
case TimeInterval.Hour:
return DateTimeInterval.Hour;
default: // ivOff
return DateTimeInterval.Off;
}
}
public static DateTimeInterval ToDateTimeInterval(this DateInterval aInterval)
{
switch (aInterval)
{
case DateInterval.Day:
return DateTimeInterval.Day;
case DateInterval.Month:
return DateTimeInterval.Month;
case DateInterval.Year:
return DateTimeInterval.Year;
default: // ivOff
return DateTimeInterval.Off;
}
}
}
In delphi I would rather do something like this
const
cDate2DateTimeInterval:array[DateInterval] of DateTimeInterval=(
DateTimeInterval.Off,
DateTimeInterval.Day,
DateTimeInterval.Month,
DateTimeInterval.Year);
cTime2DateTimeInterval:array[TimeInterval] of DateTimeInterval=(
DateTimeInterval.Off,
DateTimeInterval.MilliSecond,
DateTimeInterval.Second,
DateTimeInterval.Minute,
DateTimeInterval.Hour);
And then use these arrays to "map" the conversion. (Maybe some Snytax™ errors, but you will get the point)
Question
Wat would be a cleaner way to implement this conversion in C#, using Core3.1 ?

This may not be the most glamorous solution but I think it has the array/map kind of feel you're talking about. Use a dictionary that maps one type to another. You could create another dictionary to go backwards by flipping the types around. Usage is shown in the "Test" method below.
public static Dictionary<DateInterval, DateTimeInterval> DateToDateTime = new Dictionary<DateInterval, DateTimeInterval>()
{
{ DateInterval.Off, DateTimeInterval.Off},
{ DateInterval.Day, DateTimeInterval.Day},
{ DateInterval.Month, DateTimeInterval.Month},
{ DateInterval.Year, DateTimeInterval.Year}
};
public static void Test()
{
//This acts kind of like an array/map
DateTimeInterval converted = DateToDateTime[DateInterval.Day];
}

Since the name is identical you could do the following
public static class DateIntervalHelper
{
public static DateTimeInterval ToDateTimeInterval(this TimeInterval aInterval)
{
if (Enum.TryParse<DateTimeInterval>(aInterval.ToString(), out var #enum))
return #enum;
return DateTimeInterval.Off;
}
public static DateTimeInterval ToDateTimeInterval(this DateInterval aInterval)
{
if (Enum.TryParse<DateTimeInterval>(aInterval.ToString(), out var #enum))
return #enum;
return DateTimeInterval.Off;
}
}
Example:
https://dotnetfiddle.net/bXlBfW

A real nice way is to use the recently introduced EnumConverter. It's used to convert from any Enum to any other type (also another Enum). EnumConverter inherits the well known TypeConverter.
You can check the documentations here: https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.enumconverter?view=netcore-3.1
Sample copy-pasted from the docs:
Enum myServer = Servers.Exchange;
string myServerString = "BizTalk";
Console.WriteLine(TypeDescriptor.GetConverter(myServer).ConvertTo(myServer, typeof(string)));
Console.WriteLine(TypeDescriptor.GetConverter(myServer).ConvertFrom(myServerString));
Of course you could go the manual way, build up a Dictionary and return the the value for each key in a helper class.
The big advantage of the type/enum converter is the following: If you have some place in your code where you don't know the origin type or the target type, you can get a converter using TypeDescriptor.GetConverter and convert <U> to <T>.

You could write a generic converter:
static bool TryConvert<TSourceEnum, TDestEnum>(TSourceEnum source, out TDestEnum result)
where TSourceEnum : struct, Enum
where TDestEnum : struct, Enum
{
if (Enum.TryParse(source.ToString(), out TDestEnum r))
{
result = r;
return true;
}
result = default;
return false;
}
Usage:
if (TryConvert(DateInterval.Off, out TimeInterval timeInterval))
{
// Do something with your time interval
}
Here the string representation of the source enum value is parsed into a destination enum value.

Based on Kd's answer, and still using the delphistyle mapping arrays approach (I can because because my enums are contigous) I came up with this :
public enum DateInterval { Off, Day, Month, Year };
public enum TimeInterval { Off, MilliSecond, Second, Minute, Hour };
public enum DateTimeInterval { Off, MilliSecond, Second, Minute, Hour, Day, Month, Year };
public static class DateIntervalHelper
{
private static readonly DateTimeInterval[] dateIntervalMap =
{
DateTimeInterval.Off, DateTimeInterval.Day, DateTimeInterval.Month, DateTimeInterval.Year
};
private static readonly DateTimeInterval[] timeIntervalMap =
{
DateTimeInterval.Off, DateTimeInterval.MilliSecond, DateTimeInterval.Second, DateTimeInterval.Minute, DateTimeInterval.Hour
};
public static DateTimeInterval ToDateTimeInterval(this TimeInterval aInterval)
=> timeIntervalMap[(int)aInterval];
public static DateTimeInterval ToDateTimeInterval(this DateInterval aInterval)
=> dateIntervalMap[(int)aInterval];
}
I actually tested this and can confirm it works :>
Using this is also easy, check overloaded functions at the end of the source:
public static DateTime StartOfInterval(DateTime aInput, DateTimeInterval aInterval)
{
switch (aInterval)
{
case DateTimeInterval.MilliSecond:
return new DateTime(aInput.Year, aInput.Month, aInput.Day, aInput.Hour, aInput.Minute, aInput.Second, aInput.Millisecond);
case DateTimeInterval.Second:
return new DateTime(aInput.Year, aInput.Month, aInput.Day, aInput.Hour, aInput.Minute, aInput.Second, 0);
case DateTimeInterval.Minute:
return new DateTime(aInput.Year, aInput.Month, aInput.Day, aInput.Hour, aInput.Minute, 0, 0);
case DateTimeInterval.Hour:
return aInput.BeginOfHour();
case DateTimeInterval.Day:
return aInput.BeginOfDay();
case DateTimeInterval.Month:
return aInput.BeginOfMonth();
case DateTimeInterval.Year:
return aInput.BeginOfYear();
default: // ivOff
return aInput;
}
}
public static DateTime StartOfInterval(DateTime aInput, DateInterval aInterval)
{
return StartOfInterval(aInput, aInterval.ToDateTimeInterval());
}
public static DateTime StartOfInterval(DateTime aInput, TimeInterval aInterval)
{
return StartOfInterval(aInput, aInterval.ToDateTimeInterval());
}

Related

C# Use int constants vs Enums without cast

I have some int constants grouped in several Enum, like:
enum myEnum{
OBJECT_A = 10, OBJECT_B = 13 };
Now I have several functions which take this Enums and do something, like:
void myfunc(myEnum e)
{ .... }
In my code, I need to use myfunc in both these two ways:
myfunc(myEnum.OBJECT_A);
myfunc(13);
This gives an error because ints aren't casted to Enum implicitly.
What do you recommend as a best practice to do this preserving readability of the code?
An obvious solution is to use myfunc((myEnum)13); but this is boring because one needs to cast the int every time and the code gets heavy.
So far what I did is (avoiding enums at all):
using EChannelInt = System.Int32;
public static class EChannel
{
public static readonly int CH_CONNECTION = 10;
public static readonly int CH_DATA = 50;
}
public void doit(EChannelInt ch)
{ .... }
doit(EChannel.CH_DATA);
doit(10);
which works, but I don't like it very much because it seems like a "trick" or renaming thigs. What do you suggest? Perhaps "implicit operator" may be useful?
You can overload myFunc:
void myFunc(int i)
{
myFunc((myEnum)i);
}
You can use type-safe-enum pattern and you can override the implicit cast operator.
public class EChannel
{
public int Value {get; private set;};
public static readonly EChannel CH_CONNECTION = new EChannel(10);
public static readonly EChannel CH_DATA = new EChannel(50);
private EChannel(int value)
{
Value = value;
}
public static implicit operator EChannel(int a)
{
EChannel eChannel = null;
switch (a) // this need to be changed to something more light
{
case 10:
eChannel = CH_CONNECTION;
break;
case 50:
eChannel = CH_DATA;
break;
default:
throw new Exception("Constant don't exists");
}
return eChannel;
}
}
And you use it like this
public void doit(EChannel ch)
{ .... }
doit(EChannel.CH_DATA);
doit(10);
How about an overload?
void myfunc(int i)
{
myfunc((myEnum)i);
}
(If you don't have control of the class, you can do it as an extension method.)
I would stick with the enumeration values as much as possible and only cast to int in a narrow scope when absolutely necessary (if at all).
However, if you insist on mixing integers and enumeration values then you should consider defining the enum members from the integers so that they are guaranteed to be consistent.
Example:
public static class EChannel
{
public const int CH_CONNECTION = 10;
}
public enum myEnum
{
CH_CONNECTION = EChannel.CH_CONNECTION
}

Creating a custom property class for multiple re-use within a class

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 there a structure that handles Timeblocks?

I want to handle Timeblocks, that means a set of two DateTimes which represent for example the presence of employees. Is there already any structure that i can use to search for a block before or after a specific time?
There are many ways i can imagine to express the situation, like i said with two DateTimes for start and end or with a Datetime for start and a TimeSpan. But i want them to be handled in a kind of Collection. So is there anything similar that i can use or do i have to implement it completely on my own?
Thanks
this library is a great thing - may you get inspired
Time Period Library for .NET
The class:
public class TimePeriod
{
public DateTime Oldest { get; set; }
public DateTime Newest { get; set; }
public TimePeriod(DateTime oldest, DateTime newest)
{
Oldest = oldest;
Newest = newest;
}
public bool Contains (DateTime time)
{
return Oldest.CompareTo(time) <= 0 && Newest.CompareTo(time) >= 0;
}
public bool IsAfter(DateTime time)
{
return Newest.CompareTo(time) <= 0;
}
public bool IsBefore(DateTime time)
{
return Oldest.CompareTo(time) >= 0;
}
}
The Test:
class Program
{
static void Main(string[] args)
{
var period = new TimePeriod(
DateTime.Now.AddDays(-2),
DateTime.Now.AddDays(1));
var date = DateTime.Now;
var contains = period.Contains(date); // true
var isBefore = period.IsBefore(date); // false
var isAfter = period.IsAfter(date); // false
date = DateTime.Now.AddDays(-10);
contains = period.Contains(date); // false
isBefore = period.IsBefore(date); // true
isAfter = period.IsAfter(date); // false
date = DateTime.Now.AddDays(10);
contains = period.Contains(date); // false
isBefore = period.IsBefore(date); // false
isAfter = period.IsAfter(date); // true
}
}
Now you can use collections and linq with extensions methods and lambda expression to look for time blocks.
This is not built-in. If you want to implement this yourself you probably want to create a struct. This will give you value-type copy semantics. Such a value behaves just like built-in types like int or DateTime. Very intuitive to use.
You may take a look at TimeSpan. Thats a struct to handle a "Timeblock"
I've used a DateSpan structure before. You can extend is a much as one likes, but this will give you a starting point.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace StackOverFlowDateSpan
{
[StructLayout(LayoutKind.Auto)]
[Serializable]
public struct DateSpan : IComparable, IComparable<DateSpan>, IEquatable<DateSpan>
{
public DateSpan(DateTime start, DateTime end)
: this()
{
Start = start;
End = end;
}
#region Properties
public TimeSpan Duration
{
get { return TimeSpan.FromTicks((End - Start).Ticks); }
}
public DateTime End { get; private set; }
public DateTime Start { get; private set; }
#endregion
public int CompareTo(DateSpan other)
{
long otherTicks = other.Duration.Ticks;
long internalTicks = Duration.Ticks;
return internalTicks > otherTicks ? 1 : (internalTicks < otherTicks ? -1 : 0);
}
public bool Equals(DateSpan other)
{
return End.Equals(other.End) && Start.Equals(other.Start);
}
public int CompareTo(object other)
{
if (other == null)
{
return 1;
}
if (!(other is DateSpan))
{
throw new ArgumentNullException("other");
}
return CompareTo((DateSpan)other);
}
public override bool Equals(object other)
{
if (ReferenceEquals(null, other))
{
return false;
}
return other is DateSpan && Equals((DateSpan)other);
}
public override int GetHashCode()
{
unchecked
{
return (End.GetHashCode() * 397) ^ Start.GetHashCode();
}
}
public static bool operator ==(DateSpan left, DateSpan right)
{
return left.Equals(right);
}
public static bool operator !=(DateSpan left, DateSpan right)
{
return !left.Equals(right);
}
private sealed class EndStartEqualityComparer : IEqualityComparer<DateSpan>
{
#region IEqualityComparer<DateSpan> Members
public bool Equals(DateSpan x, DateSpan y)
{
return x.End.Equals(y.End) && x.Start.Equals(y.Start);
}
public int GetHashCode(DateSpan obj)
{
unchecked
{
return (obj.End.GetHashCode() * 397) ^ obj.Start.GetHashCode();
}
}
#endregion
}
private static readonly IEqualityComparer<DateSpan> _endStartComparerInstance = new EndStartEqualityComparer();
public static IEqualityComparer<DateSpan> EndStartComparer
{
get { return _endStartComparerInstance; }
}
}
}
Thanks for the help! I will tae a closer look at the TimePeriod Library and do some experiments with Linq. I already have an approch that implements binary search, so if someones interested you can write me ;)

What pattern should I use to express a Hierarchical Enum?

I'm experimenting with an API for publishing values at a given time (tuples of value and time). These samples will be used by a data viewer (e.g. a graph).
I want to associate the value with a Quantity and a Unit, for example length in meters. That way my "viewer" can scale it appropriately.
I'm looking for a sort of hierarchical enum, like this:
enum Quantity
{
Mass.Kg,
Mass.g,
Length.m,
Length.mm
}
But this doesn't exist in C#.
I'm not sure the best pattern to express this and I've come up with the following. Is there a recognised, or better way to do this?
using System;
using Moq;
namespace ConsoleApplication26
{
class Program
{
static void Main(string[] args)
{
//use a Mock to play with the API
Mock<ITelemetryPublisherFactory> mockTelemetryPublisherFactory = new Mock<ITelemetryPublisherFactory>();
var telemetryPublisherFactory = mockTelemetryPublisherFactory.Object;
//example usages
var massTelemetryPublisher = telemetryPublisherFactory.GetChannelSamplePublisher<Double>("My Mass", Mass.Kg);
massTelemetryPublisher.PublishChannelSampleAtTimeNow(83.4);
var lengthTelemetryPublisher = telemetryPublisherFactory.GetChannelSamplePublisher<Int32>("My Height", Length.μm);
lengthTelemetryPublisher.PublishChannelSampleAtTimeNow(1800000);
//10 years time..
lengthTelemetryPublisher.PublishChannelSampleAtTimeNow(1800000);
massTelemetryPublisher.PublishChannelSampleAtTimeNow(120.1);
}
}
public interface ITelemetryPublisherFactory
{
ITelemetryPublisher<T> GetChannelSamplePublisher<T>(String channelName, Quantity quantity);
}
public interface ITelemetryPublisher<T>
{
void PublishChannelSampleAtTimeNow(T sampleValue);
}
public abstract class Quantity {}
public class Mass : Quantity
{
private enum Unit
{
g,
Kg
}
private readonly Unit _unit;
private Mass(Unit unit)
{
_unit = unit;
}
public static Quantity Kg {get { return new Mass(Unit.Kg); }}
public static Quantity g { get { return new Mass(Unit.g); } }
public override string ToString()
{
return String.Format("Mass.{0}", _unit);
}
}
public class Length : Quantity
{
private enum Unit
{
m,
mm,
μm,
beardSecond
}
private readonly Unit _unit;
private Length(Unit unit)
{
_unit = unit;
}
public static Quantity m { get { return new Length(Unit.m); } }
public static Quantity mm { get { return new Length(Unit.mm); } }
public static Quantity μm { get { return new Length(Unit.μm); } }
public static Quantity beardSecond { get { return new Length(Unit.beardSecond); } }
public override string ToString()
{
return String.Format("Length.{0}", _unit);
}
}
}
I think it's better to create a Unit class for the unit of measure and a Quantity class that associates a unit of measure with an amount. Look at the Quantity pattern for the idea. Since you also want to record the "type" of the unit of measure, you could create a UnitType class that records that information:
public sealed partial class UnitType {
public string Name { get; private set; }
public UnitType(string name) {
Name = name;
}
}
public sealed partial class Unit {
public string Name { get; private set; }
public UnitType Type { get; private set; }
public Unit(string name, UnitType type) {
Name = name;
Type = type;
}
}
(You should make them proper value types by overriding Equals and GetHashCode)
The Unit class can be extended to provide for e.g. conversions, compound units, formatting and parsing.
Then, you can define the common cases inside the classes:
public partial class UnitType {
public static readonly UnitType Mass = new UnitType("Mass");
public static readonly UnitType Length = new UnitType("Length");
}
public partial class Unit {
public static readonly Unit Grams = new Unit("g", UnitType.Mass);
public static readonly Unit Kilos = new Unit("kg", UnitType.Mass);
// ...
}
Or define your "hierarchies" with static classes:
public static class Mass {
public static readonly UnitType Type = new UnitType("Mass");
public static readonly Unit Grams = new Unit("g", Type);
public static readonly Unit Kilos = new Unit("kg", Type);
...
}
public static class Length ...
The Quantity class would also be an immutable value type (just showing its usage):
var eniacWeight = new Quantity(27, Mass.Tons);
Or you could use extension methods to create Quantitys:
var eniacWeight = 27.Tons();
(from ENIAC)
This is not possible. Enums are primitive types and cannot inherit from other enums, as inheritance is a property of objects.
Hierarchical enum isn't possible, as noted above. If you're exclusively using metric, though, you can utilise standard prefixes if it helps.
enum MeasurementUnits
{
Gram,
Metre,
Litre,
Hectare
// etc
}
enum MeasurementPrefix
{
Milli,
Natural,
Kilo,
Mega
// etc
}
This may not be precisely what you want, but it will provide the type of 'grouping' that you might be looking for (e.g. group measurements that are about length, weight etc by checking their 'units' value).
Your suggested approach seems reasonable to me, and I use something similar in a project of mine. However, I keep the actual value part of the object, and I use struct instead of class, since they are naturally value types. Inheritance is not necessary here (and not possible with structs, anyways), so I use an interface to create a contract and act as a constraint when needed (I called it IUnitOfMeasure).
I do not recommend creating one enum with all the units of the various types of measurement combined; it is hell validating the unit to make sure someone didn't reference a Mass unit when working with Length.
public interface IUnitOfMeasure<TThis>
where TThis : IUnitOfMeasure<TThis>
{
TThis ConvertTo(TThis value);
}
public struct Mass : IUnitOfMeasure<Mass>
{
public enum Units
{
Gram,
Kilogram
}
private double _value;
private Mass.Units _unit;
public double Value { get { return _value; } }
public Mass.Units Unit { get { return _unit; } }
public Mass(double value, Mass.Units unit)
{
_value = value;
_unit = unit;
}
public Mass ConvertTo(Mass value)
{
switch(value.Unit)
{
case Units.Gram:
return new Mass(Unit == Units.Gram ? Value : Value/1000, Units.Gram);
case Units.Kilogram:
return new Mass(Unit == Units.Gram ? Value*1000 : Value, Units.Kilogram);
default:
throw new NotImplementedException();
}
}
public override string ToString()
{
return string.Format("{0} {1}", Value, Unit);
}
public static readonly Mass G = new Mass(0, Units.Gram);
public static readonly Mass Kg = new Mass(0, Units.Kilogram);
}
Usage:
var kg = new Mass(5.0, Mass.Units.Kilogram);
Console.WriteLine(kg); // writes "5 Kilogram"
var g = kg.ConvertTo(Mass.G);
Console.WriteLine(g); // writes ".005 Gram"
If you don't care about keeping the value, and just want to keep enum/static values in a central place:
public static class UnitOfMeasure
{
public enum Mass
{
Gram,
Kilogram
}
public enum Length
{
Meter,
Kilometer
}
// etc.
}
Usage: var unit = UnitOfMeasure.Mass.Kilogram;
You cannot introduce inheritance with enums. Enums are just a convenience mechanism to allow you to use meaningful textual identifiers in your code. From The code you have, I suggest you either use an enum like;
public enum UnitOfMeasure
{
MassGrams,
MassKg,
LengthMM,
LengthCM,
. . .
}
Or split it out to where it's appropriate, so that Mass and Length are defined separately for example.
The 'inheritance' is just something you've introduced in your thinking about this problem, but it isn't necessary to your solution. When you want to deal with Mass, you only look at the flags/enums appropriate to mass.

Accessor with different set and get types?

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);
}
}

Categories

Resources