C# 枚举转换,最干净的方式
C# enum conversion, cleanest way
背景
具有 delphi 背景,我习惯于使用常量和常量数组等来修复很多问题。此外 Delphi allpws 使用助手 类 对枚举进行类型转换。
现在看一下 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 };
如您所见,这些枚举之间可以进行逻辑转换,我已经成功地使用以下方法实现了这一点:
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;
}
}
}
在delphi我宁愿做这样的事情
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);
然后使用这些数组来“映射”转换。 (可能会出现一些 Snytax™ 错误,但您会明白这一点)
问题
Wat 是在 C# 中使用 Core3.1 实现此转换的更简洁的方法吗?
由于名称相同,您可以执行以下操作
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;
}
}
示例:
一个真正好的方法是使用最近推出的 EnumConverter
。它用于从任何 Enum
转换为任何其他 type
(还有另一个 Enum
)。 EnumConverter
继承了众所周知的 TypeConverter
.
您可以在此处查看文档:https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.enumconverter?view=netcore-3.1
从文档中复制粘贴的示例:
Enum myServer = Servers.Exchange;
string myServerString = "BizTalk";
Console.WriteLine(TypeDescriptor.GetConverter(myServer).ConvertTo(myServer, typeof(string)));
Console.WriteLine(TypeDescriptor.GetConverter(myServer).ConvertFrom(myServerString));
当然你可以采用手动方式,建立一个 Dictionary
和 return 帮助程序 class.
中每个键的值
type/enum 转换器的最大优点如下:如果您的代码中有一些地方您不知道源类型或目标类型,您可以使用 TypeDescriptor.GetConverter
并将 <U>
转换为 <T>
.
您可以编写一个通用转换器:
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;
}
用法:
if (TryConvert(DateInterval.Off, out TimeInterval timeInterval))
{
// Do something with your time interval
}
此处将源枚举值的字符串表示形式解析为目标枚举值。
这可能不是最迷人的解决方案,但我认为它具有您所说的 array/map 那种感觉。使用将一种类型映射到另一种类型的字典。您可以通过翻转类型来创建另一个字典以向后移动。用法在下面的“测试”方法中显示。
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];
}
基于 Kd 的回答,并且仍然使用 delphistyle 映射数组方法(我可以,因为我的枚举是连续的)我想到了这个:
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];
}
我实际测试过这个并且可以确认它有效:>
使用这个也很简单,查看源码末尾的重载函数:
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());
}
背景
具有 delphi 背景,我习惯于使用常量和常量数组等来修复很多问题。此外 Delphi allpws 使用助手 类 对枚举进行类型转换。 现在看一下 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 };
如您所见,这些枚举之间可以进行逻辑转换,我已经成功地使用以下方法实现了这一点:
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;
}
}
}
在delphi我宁愿做这样的事情
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);
然后使用这些数组来“映射”转换。 (可能会出现一些 Snytax™ 错误,但您会明白这一点)
问题
Wat 是在 C# 中使用 Core3.1 实现此转换的更简洁的方法吗?
由于名称相同,您可以执行以下操作
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;
}
}
示例:
一个真正好的方法是使用最近推出的 EnumConverter
。它用于从任何 Enum
转换为任何其他 type
(还有另一个 Enum
)。 EnumConverter
继承了众所周知的 TypeConverter
.
您可以在此处查看文档:https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.enumconverter?view=netcore-3.1
从文档中复制粘贴的示例:
Enum myServer = Servers.Exchange;
string myServerString = "BizTalk";
Console.WriteLine(TypeDescriptor.GetConverter(myServer).ConvertTo(myServer, typeof(string)));
Console.WriteLine(TypeDescriptor.GetConverter(myServer).ConvertFrom(myServerString));
当然你可以采用手动方式,建立一个 Dictionary
和 return 帮助程序 class.
type/enum 转换器的最大优点如下:如果您的代码中有一些地方您不知道源类型或目标类型,您可以使用 TypeDescriptor.GetConverter
并将 <U>
转换为 <T>
.
您可以编写一个通用转换器:
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;
}
用法:
if (TryConvert(DateInterval.Off, out TimeInterval timeInterval))
{
// Do something with your time interval
}
此处将源枚举值的字符串表示形式解析为目标枚举值。
这可能不是最迷人的解决方案,但我认为它具有您所说的 array/map 那种感觉。使用将一种类型映射到另一种类型的字典。您可以通过翻转类型来创建另一个字典以向后移动。用法在下面的“测试”方法中显示。
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];
}
基于 Kd 的回答,并且仍然使用 delphistyle 映射数组方法(我可以,因为我的枚举是连续的)我想到了这个:
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];
}
我实际测试过这个并且可以确认它有效:>
使用这个也很简单,查看源码末尾的重载函数:
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());
}