Convert System.DayOfWeek into Microsoft.Office.Interop.Outlook.OlDaysOfWeek - c#

Is there a possibility to directly convert a value of System.DayOfWeek into a value of Microsoft.Office.Interop.Outlook.OlDaysOfWeek. Something like:
var day = DayOfWeek.Friday;
OlDaysOfWeek days = ConvertToDaysOfWeek(day);

To do this without using string manipulation, here's an option:
public OlDaysOfWeek ConvertToDaysOfWeek(DayOfWeek day)
{
return (OlDaysOfWeek)Math.Pow(2, (int)day);
}

You can try this:
var olDay = (OlDaysOfWeek) Enum.Parse(typeof(OlDaysOfWeek), $"ol{systemDay}");

A simple switch statement would probably be most performant:
public OlDaysOfWeek ConvertToDaysOfWeek(DayOfWeek day)
{
switch (day)
{
case DayOfWeek.Monday: return OlDaysOfWeek.olMonday;
case DayOfWeek.Tuesday: return OlDaysOfWeek.olTuesday;
case DayOfWeek.Wednesday: return OlDaysOfWeek.olWednesday;
case DayOfWeek.Thursday: return OlDaysOfWeek.olThursday;
case DayOfWeek.Friday: return OlDaysOfWeek.olFriday;
case DayOfWeek.Saturday: return OlDaysOfWeek.olSaturday;
case DayOfWeek.Sunday: return OlDaysOfWeek.olSunday;
default: throw new ArgumentOutOfRangeException("What day is this?", "day");
}
}
Alternatively, you could probably parse the value and return the mapped value based on the enum value name.
public OlDaysOfWeek ConvertToDaysOfWeek(DayOfWeek day)
{
return (OlDaysOfWeek) Enum.Parse(typeof(OlDaysOfWeek), "ol" + day.ToString());
}
The OlDaysOfWeek enum utilises a power-of-2 sequence, which is typically used when combining values as bitwise flags. DaysOfWeek has a simple linear sequence reflected as 0-6 - this is why you can't compare using the backing int value

Finally I found the following solution. Thanks for the hints.
public static OlDaysOfWeek AsDaysOfWeek(this DayOfWeek dayOfWeek)
{
return (OlDaysOfWeek)(1 << (int)dayOfWeek);
}
To be used like this:
var day = DayOfWeek.Friday;
OlDaysOfWeek days = day.AsDaysOfWeek();
Additionally these are the unit tests in NUnit for the method:
[TestCase(DayOfWeek.Monday, OlDaysOfWeek.olMonday)]
[TestCase(DayOfWeek.Tuesday, OlDaysOfWeek.olTuesday)]
[TestCase(DayOfWeek.Wednesday, OlDaysOfWeek.olWednesday)]
[TestCase(DayOfWeek.Thursday, OlDaysOfWeek.olThursday)]
[TestCase(DayOfWeek.Friday, OlDaysOfWeek.olFriday)]
[TestCase(DayOfWeek.Saturday, OlDaysOfWeek.olSaturday)]
[TestCase(DayOfWeek.Sunday, OlDaysOfWeek.olSunday)]
public void AsDaysOfWeek(DayOfWeek dayOfWeek, OlDaysOfWeek expectedResult)
{
var result = dayOfWeek.AsDaysOfWeek();
Assert.That(result, Is.EqualTo(expectedResult));
}

Related

How to sort a string array with integers and strings in?

I have a string array:
string[] face = {"A","2","3","4","5","6","7","8","9","10","J","Q","K" };
I randomized it and now I am trying to sort it back to what it was.
I tried the Array.Sort() method but it didn't work.
Any ideas how I can achieve this?
You could use LINQs OrderBy method
var ordered = random.OrderBy(face => CardValue(face)).ToArray();
with the following CardValue method
int CardValue(string card)
{
switch(card)
{
case "A":
return 1;
case "J":
return 11;
case "Q":
return 12;
case "K":
return 13;
default:
return int.Parse(card);
}
}
just to give you a gist of how this could be achieved. This sample is not really production-ready, though.

Returning an array in case switching C#

I am trying to return an array with a date [sStartMonth, sStartDay, sStartYear] for a specific case, for example: case: "Today" will return {"June", "3", "2015"}.
I am trying something like this but fail:
public static string[] SetStartDate(string sStartDateFilter)
{
switch (sStartDateFilter)
{
case "Today":
DateTime currentDate = DateTime.Now;
string sStartMonth = currentDate.ToString("MMMM");
string sStartDay = currentDate.Day.ToString();
string sStartYear = currentDate.Year.ToString();
return {sStartMonth, sStartDay, sStartYear};
}
}
To construct an array in-line you need the full syntax, the short-hand syntax you're using is only allowed when explicitly declaring an array and giving it a value in the same statement.
So this is what you want:
return new[] { sStartMonth, sStartDay, sStartYear };
Something like:
switch (sStartDateFilter)
{
case "Today":
return new[] { sStartMonth, sStartDay, sStartYear };
default:
// return something here or throw
You will need to return something for the default case too, or throw a new ArgumentOutOfRangeException("sStartDateFilter") or you will get a compiler error as not all paths will return a value.
To combine the answer of #Lasse V. Karlsen with my potential answer:
public static string[] GetStartDate(string sStartDateFilter)
{
DateTime currentDate = DateTime.Now;
switch (sStartDateFilter)
{
case "Today":
return new string[]{ currentDate.ToString("MMMM"), currentDate.Day.ToString(), currentDate.Year.ToString()};
case "Tomorrow":
currentDate.AddDays(1);
return new string[]{ currentDate.ToString("MMMM"), currentDate.Day.ToString(), currentDate.Year.ToString()};
case "Yesterday":
currentDate.AddDays(-1);
return new string[]{ currentDate.ToString("MMMM"), currentDate.Day.ToString(), currentDate.Year.ToString()};
default:
// all other cases
}
}
EDIT:
I know, that I should move the line return new string[]{ currentDate.ToString("MMMM"), currentDate.Day.ToString(), currentDate.Year.ToString()}; into a separate function, but this is only a simple example

C# - Get switch value if in default case

Help please, I have this case:
switch(MyFoo()){
case 0: //...
break;
case 1: //...
break;
case 2: //...
break;
default:
// <HERE>
break;
}
As you can see the switch gets the value directly from a method without saving it as a variable.
Is it possible to get which value fires the default case?
For example if MyFoo() returns 7, how can I get that value?
I want to avoid to save the method result as a variable, is there a way to get the switch value from inside a case? Something like this:
default:
this.SwitchValue // <<--
break;
Thank you for reading,
~Saba
Is there a way to get the switch value from inside a case?
The only (proper) way is actually to store the result of MyFoo() in a variable.
var fooResult = MyFoo();
switch (fooResult)
{
case 0:
...
break;
...
default:
handleOthersCase(fooResult);
break;
}
This code is readable and understandable and have no extra cost (As #SheldonNeilson says: It's on the stack anyway).
Also, the MSDN first example about switch totally look like this. You can also find informations int the language specification.
You also can make your own switch based on a dictionary, but the only advantage I see is that you can use it for complex cases (any kind of object instead of string/int/...). Performance is a drawback.
It may look like this:
public class MySwitch<T> : Dictionary<T, Action<T>>
{
private Action<T> _defaultAction;
public void TryInvoke(T value)
{
Action<T> action;
if (TryGetValue(value, out action))
{
action(value);
}
else
{
var defaultAction = _defaultAction;
if (defaultAction != null)
{
defaultAction(value);
}
}
}
public void SetDefault(Action<T> defaultAction)
{
_defaultAction = defaultAction;
}
}
And be used like this:
var mySwitch = new MySwitch<int>();
mySwitch.Add(1, i => Console.WriteLine("one")); // print "one"
mySwitch.Add(2, i => Console.WriteLine("two")); // print "two"
mySwitch.SetDefault(i => Console.WriteLine("With the digits: {0}", i)); // print any other value with digits.
mySwitch.TryInvoke(42); // Output: "With the digits: 42"
Or based on this response, this:
public class MySwitch2<T>
{
private readonly T _input;
private bool _done = false;
private MySwitch2(T input)
{
_input = input;
}
public MySwitch2<T> On(T input)
{
return new MySwitch2<T>(input);
}
public MySwitch2<T> Case(T caseValue, Action<T> action)
{
if (!_done && Equals(_input, caseValue))
{
_done = true;
action(_input);
}
return this;
}
public void Default(Action<T> action)
{
if (!_done)
{
action(_input);
}
}
}
Can be used like that:
MySwitch2<int>.On(42)
.Case(1, i => Console.WriteLine("one"))
.Case(2, i => Console.WriteLine("two"))
.Default(i => Console.WriteLine("With the digits: {0}", i));
I can't see a reason as well why to use it like that but may be a work around will be like this:
int x;
switch ( x = MyFoo())
{
case 0: //...
break;
case 1: //...
break;
case 2: //...
break;
default:
var s = x; // Access and play with x here
break;
}
No, this isn't possible.
You can assign the value to variable inside switch, if you want to look like reinventing the wheel:
int b;
.....
switch (b = MyFoo())
{
case 1:
break;
case 2:
break;
default:
//do smth with b
break;
}
The easiest way is to save the result of MyFoo() as a variable.. But if you don't want to do that you could do:
switch(MyFoo()){
case 0: //...
break;
case 1: //...
break;
case 2: //...
break;
default:
this.SwitchCase = MyFoo();
break;
}
Although I would advise against this and say save the value as a variable to save your program the extra work.
Saving the value of MyFoo as a variable becomes more important the more complex the example gets as the value of MyFoo could have changed between the switch and default case.
Also this will only work where MyFoo has no side-effects and obviously must always return the same value for any given parameter.
for example the following would work:
Private int MyFoo()
{
return 3;
}
But the following would not:
private int MyFoo()
{
Random r = new Random();
return r.Next(5);
}
This is possible now.
https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#property-patterns
Example:
int? TryGetColumnIndex(string columnName)
=> GetValue(columnName)
switch
{ var result when result > -1 => result, _ => new int?() };
result will capture the result of GetValue.
Even cooler, you can do propery checks.
i.e instead of when result > -1 you can even say when result.ToString().Length > 2 and such.

Format TimeSpan in DataGridView column

I've seen these questions but both involve methods that aren't available in the CellStyle Format value. I only want to show the hours and minutes portion (16:05); not the seconds as well (16:05:13). I tried forcing the seconds value to zero but still got something like 16:05:00. Short of using a kludge like providing a string or a DateTime (and only showing the hour/minutes part) is there any way I can get the formatting to do what I want.
I just discovered this myself. Unfortunately, the solution is pretty involved. The good news is that it works.
Firstly, you need an ICustomFormatter implementation that deals with TimeSpan values. The .NET framework does not include such a type out-of-the-box; I am guessing this is because Microsoft didn't want to have to deal with the ambiguity involved in formatting a TimeSpan (e.g., does "hh" mean total hours or only the hour component?) and the ensuing onslaught of support issues that would arise when these ambiguities confused developers.
That's OK -- just implement your own. Below is a sample class I wrote that uses basically the same custom format strings as DateTime (those that were applicable, anyway)*:
class TimeSpanFormatter : IFormatProvider, ICustomFormatter
{
private Regex _formatParser;
public TimeSpanFormatter()
{
_formatParser = new Regex("d{1,2}|h{1,2}|m{1,2}|s{1,2}|f{1,7}", RegexOptions.Compiled);
}
#region IFormatProvider Members
public object GetFormat(Type formatType)
{
if (typeof(ICustomFormatter).Equals(formatType))
{
return this;
}
return null;
}
#endregion
#region ICustomFormatter Members
public string Format(string format, object arg, IFormatProvider formatProvider)
{
if (arg is TimeSpan)
{
var timeSpan = (TimeSpan)arg;
return _formatParser.Replace(format, GetMatchEvaluator(timeSpan));
}
else
{
var formattable = arg as IFormattable;
if (formattable != null)
{
return formattable.ToString(format, formatProvider);
}
return arg != null ? arg.ToString() : string.Empty;
}
}
#endregion
private MatchEvaluator GetMatchEvaluator(TimeSpan timeSpan)
{
return m => EvaluateMatch(m, timeSpan);
}
private string EvaluateMatch(Match match, TimeSpan timeSpan)
{
switch (match.Value)
{
case "dd":
return timeSpan.Days.ToString("00");
case "d":
return timeSpan.Days.ToString("0");
case "hh":
return timeSpan.Hours.ToString("00");
case "h":
return timeSpan.Hours.ToString("0");
case "mm":
return timeSpan.Minutes.ToString("00");
case "m":
return timeSpan.Minutes.ToString("0");
case "ss":
return timeSpan.Seconds.ToString("00");
case "s":
return timeSpan.Seconds.ToString("0");
case "fffffff":
return (timeSpan.Milliseconds * 10000).ToString("0000000");
case "ffffff":
return (timeSpan.Milliseconds * 1000).ToString("000000");
case "fffff":
return (timeSpan.Milliseconds * 100).ToString("00000");
case "ffff":
return (timeSpan.Milliseconds * 10).ToString("0000");
case "fff":
return (timeSpan.Milliseconds).ToString("000");
case "ff":
return (timeSpan.Milliseconds / 10).ToString("00");
case "f":
return (timeSpan.Milliseconds / 100).ToString("0");
default:
return match.Value;
}
}
}
We're not finished yet. With this type in place, you are equipped to assign a custom formatter to the column in your DataGridView that you want to use for displaying your TimeSpan values.
Let's say that column is called "Time"; then you would do this:
DataGridViewColumn timeColumn = dataGridView.Columns["Time"];
timeColumn.DefaultCellStyle.FormatProvider = new TimeSpanFormatter();
timeColumn.DefaultCellStyle.Format = "hh:mm";
So now you're set up, right?
Well, for some odd reason, you're still not 100% of the way there. Why custom formatting can't kick in at this point, I honestly couldn't tell you. But we're almost done. The one final step is to handle the CellFormatting event to get this new functionality we've written to actually take effect:
private void dataGridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
var formatter = e.CellStyle.FormatProvider as ICustomFormatter;
if (formatter != null)
{
e.Value = formatter.Format(e.CellStyle.Format, e.Value, e.CellStyle.FormatProvider);
e.FormattingApplied = true;
}
}
At last, we're finished. Setting the DefaultCellStyle.Format property of the DataGridViewColumn you want formatted according to your custom rules should now work as expected.
*So, "h"/"hh" for hours, "m"/"mm" for minutes. etc.
It is possible to achieve the effect same by just using the CellFormatting event.
private void dataGridView_CellFormatting(object sender,
DataGridViewCellFormattingEventArgs e)
{
if (e.Value != null && e.Value != DBNull.Value)
e.Value = ((TimeSpan)e.Value).Hours.ToString("00") + ":" +
((TimeSpan)e.Value).Minutes.ToString("00");
}
This obviously is not as comprehensive a solution, but quite quick.
Try the following code
dataGridView1.Columns["columnName"].DefaultCellStyle.Format = "hh\\:mm";
I don't know how to set the format of the cell to show only hours and minutes. I'd suggest you set the format of the cell to string and format the value like this:
String.Format("{0:D2}:{1:D2}",
DateTime.Now.TimeOfDay.Hours, DateTime.Now.TimeOfDay.Minutes);
Use format string "hh\\:mm".
e.g
YourGrid.Column[index].DefaultCellStyle.Format = "hh\\:mm"
Try another approach. Just add to your class binding to the datagridview properties like for instance LastPacketAtTimeDelayAsStr.
Let's say you have some class that has it...
public DateTime? LastPacketAtTime { get; set; }
public TimeSpan? LastPacketAtTimeDelay
{
get
{
if (LastPacketAtTime.HasValue)
{
var ts = DateTime.Now - LastPacketAtTime.Value;
return ts;
}
return null;
}
}
public string LastPacketAtTimeDelayAsStr
{
get
{
if (LastPacketAtTimeDelay.HasValue)
{
var hours = LastPacketAtTimeDelay.Value.Hours.ToString("00");
var minutes = LastPacketAtTimeDelay.Value.Minutes.ToString("00");
var seconds = LastPacketAtTimeDelay.Value.Seconds.ToString("00");
return $"{LastPacketAtTimeDelay.Value.Days} days {hours}:{minutes}:{seconds}";
}
return null;
}
}
And after that just bind the LastPacketAtTimeDelayAsStr to the DataGridView column you need which has String datatype.
And that's it!

Can't cast 2nd Enum value to int?

I don't get this. I was able to cast my first enum value to int but not the second?
public enum PayPalTransactionType
{
Authorization = 0, // Debit
Capture = 1, // Credit
Refund = 2,
Void = 3
}
public string GetPayPalTransCode(PayPalServiceBase.PayPalTransactionType payPalTransactionType)
{
string actionCode = string.Empty;
switch (payPalTransactionType)
{
case (int)PayPalServiceBase.PayPalTransactionType.Authorization:
actionCode = "Debit";
break;
case (int)PayPalServiceBase.PayPalTransactionType.Capture:
actionCode = "Credit";
break;
}
return actionCode;
}
on my 2nd case statement I get this casting error:
Cannot implicitly convert type int
to PayPalTransactionType. An
explicit conversion exists (are you
missing a cast?)
Why are you trying to cast in the first place? Just leave it as the enum value everywhere:
public string GetPayPalTransCode
(PayPalServiceBase.PayPalTransactionType payPalTransactionType)
{
string actionCode = string.Empty;
switch (payPalTransactionType)
{
case PayPalServiceBase.PayPalTransactionType.Authorization:
actionCode = "Debit";
break;
case PayPalServiceBase.PayPalTransactionType.Capture:
actionCode = "Credit";
break;
}
return actionCode;
}
Additionally, I'd have an explicit default action for unrecognised codes, and just return directly:
public string GetPayPalTransCode
(PayPalServiceBase.PayPalTransactionType payPalTransactionType)
{
switch (payPalTransactionType)
{
case PayPalServiceBase.PayPalTransactionType.Authorization:
return "Debit";
case PayPalServiceBase.PayPalTransactionType.Capture:
return "Credit";
default:
return ""; // Or throw an exception if this represents an error
}
}
Alternatively, you could use a Dictionary<PayPalTransactionType, string>.
Why are you casting to int at all? The thing you are switching on is already of the enum type!
As to the other part of the question, the reason the first cast is working is because an implicit cast from a constant int 0 to an enum type always works, whereas the other attempted cast is from a non-zero int value.
why for god's sake are you doing a cast??
public string GetPayPalTransCode(PayPalServiceBase.PayPalTransactionType payPalTransactionType)
{
switch (payPalTransactionType)
{
case (int)PayPalServiceBase.PayPalTransactionType.Authorization:
break;
case (int)PayPalServiceBase.PayPalTransactionType.Capture:
break;
}
}
bascially same type in here, isn't it?! you want to compare enum against enum, don't you?
just do
public string GetPayPalTransCode(PayPalServiceBase.PayPalTransactionType payPalTransactionType)
{
// ...
switch (payPalTransactionType)
{
case PayPalServiceBase.PayPalTransactionType.Authorization:
break;
case PayPalServiceBase.PayPalTransactionType.Capture:
break;
}
// ...
}
btw - it's not best practice to assign PayPalTransactionType.Authorization to 0. 0 should be used for parsing-fallbacks!
edit:
your code would be correct if you do
public string GetPayPalTransCode(PayPalServiceBase.PayPalTransactionType payPalTransactionType)
{
switch ((int)payPalTransactionType)
{
case (int)PayPalServiceBase.PayPalTransactionType.Authorization:
break;
case (int)PayPalServiceBase.PayPalTransactionType.Capture:
break;
}
}
which is quite ...!
Remove the (int) casts in your case statements. The switch can handle the enum values.
Since the switch is on `PayPalTransactionType', values of that type should be used in the case statements.
You don't need these casts in the first place. Just make it case PayPalServiceBase.PayPalTransactionType.Authorization, etc.
Tim,
I am not a Java/C# expert, but here is my 2 cents on the code block above ...
If you're using an enum, why do you need to have an int value, if you do, then do something like:
public enum PayPalTransactionType
{
Authorization(0, Debit),
Capture(1, Credit),
Refund(3, null),
Void(4. null);
private final int code;
public int getCode()
{return(code);}
private PayPalTransactionType(final int code, final TransactionType transactionType)
{
this.code = code;
this.transactionType = transactionType;
}
private TransactionType getTransactionType()
{return(transactionType);}
}
public enum TransactionType
{
Credit("Funds are added to the specified account."),
Debit("funds are deducted from the specified account.");
private final String description;
public String getDescription()
{return(description);}
private TransactionType(final String description)
{this.description = description;}
}
Switches are useful for a very small amount of cases. You can simply do this:
final PayPalTransactionType payPalTransactionType = PayPalTransactionType.Authorization;// this is just an example of the parameter you'd be passing in.
payPalTransactionType.getTransactionType();// an emum is a static database, simply store other things that are related to this value.
Walter
It's not the cast to int that's giving you a problem. Its the cast of (int)PayPalServiceBase.PayPalTransactionType.Capture (which is an int) back to PayPalServiceBase.PayPalTransactionType that's the problem.
You don't need the casts to int. Just use the enum directly.
switch (payPalTransactionType)
{
case PayPalServiceBase.PayPalTransactionType.Authorization:
actionCode = "Debit";
break;
case PayPalServiceBase.PayPalTransactionType.Capture:
actionCode = "Credit";
break;
}
The error occurs because your trying to implicitly convert payPalTransactionType to int. Maybe this will enlighten your problem:
switch ((int)payPalTransactionType)
{
case (int)PayPalServiceBase.PayPalTransactionType.Authorization:
actionCode = "Debit";
break;
case (int)PayPalServiceBase.PayPalTransactionType.Capture:
actionCode = "Credit";
break;
}
This first cast allows you to switch on ints instead of PayPalTransactionTypes. Since the switch statement supports enums, you don't need this cast.
Why are you casting it to an int the first place.? Just do the case statements using the enumerated type.
If you are really just looking up a string a better method would be an array of strings that you index by the enumerated type. That would be faster, less code and easier to maintain.
So something like this:
public enum PayPalTransactionType
{
Authorization = 0, // Debit
Capture = 1, // Credit
Refund = 2,
Void = 3,
Max // This must always be the last type and is used just as a marker.
}
string[] ActionCode = new string[(int)PayPalTransactionType.Max] { "Debit", "Credit", "Refund", "Void" };
public string GetPayPalTransCode(PayPalTransactionType payPalTransactionType)
{
return ActionCode[(int)payPalTransactionType];
}

Categories

Resources