[성현모] CPXV2 Init
This commit is contained in:
@ -0,0 +1,153 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SystemX.Net.Platform.Common.ExtensionMethods
|
||||
{
|
||||
public static class EmAsync
|
||||
{
|
||||
public static TResult WaitResultAsyncFunction<TResult>(this Func<Task<TResult>> function)
|
||||
{
|
||||
var task = Task.Run(() => function());
|
||||
task.Wait();
|
||||
return task.Result;
|
||||
}
|
||||
|
||||
public static void WaitAsyncFunction(this Func<Task> function)
|
||||
{
|
||||
function().Wait();
|
||||
}
|
||||
|
||||
|
||||
//private static Action WrapExceptionSafe(this Action action, Action<Exception> exceptionHandler)
|
||||
//{
|
||||
// return new Action(() =>
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// action();
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// if (exceptionHandler == null)
|
||||
// {
|
||||
// if ( FormAppCommon.UISynchronizationContext == null )
|
||||
// MessageBox.Show(ex.Message, "Exception occurred!", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
// else
|
||||
// FormAppCommon.UISynchronizationContext.Send(ignore => UnhandledExceptionHandler.ShowUnhandledException(ex), null);
|
||||
// }
|
||||
// else
|
||||
// exceptionHandler(ex);
|
||||
// }
|
||||
// });
|
||||
//}
|
||||
|
||||
|
||||
//public static Func<Task<T>> WrapExceptionSafe<T>(this Func<Task<T>> function, Action<Exception> exceptionHandler)
|
||||
//{
|
||||
// return new Func<Task<T>>(() =>
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// return function();
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// if (exceptionHandler == null)
|
||||
// {
|
||||
// if (FormAppCommon.UISynchronizationContext == null)
|
||||
// MessageBox.Show(ex.Message, "Exception occurred!", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
// else
|
||||
// FormAppCommon.UISynchronizationContext.Send(ignore => UnhandledExceptionHandler.ShowUnhandledException(ex), null);
|
||||
// }
|
||||
// else
|
||||
// exceptionHandler(ex);
|
||||
|
||||
// return null;
|
||||
// }
|
||||
// });
|
||||
|
||||
//}
|
||||
|
||||
///// <summary>
|
||||
///// 단순히 Task.Run(()=>{}) 수행시, exception 을 catch 할수 없으므로, 다음 extension 을 사용해서 해결함
|
||||
///// </summary>
|
||||
///// <param name="action"></param>
|
||||
///// <param name="exceptionHandler"></param>
|
||||
//public static Task ExceptionSafeTaskRun(this Action action, Action<Exception> exceptionHandler=null)
|
||||
//{
|
||||
// return Task.Run(WrapExceptionSafe(action, exceptionHandler));
|
||||
//}
|
||||
//public static Task<T> ExceptionSafeTaskRun<T>(this Func<Task<T>> function, Action<Exception> exceptionHandler=null)
|
||||
//{
|
||||
// return Task.Run(WrapExceptionSafe(function, exceptionHandler));
|
||||
//}
|
||||
|
||||
|
||||
//private static void HandleException(this Task task)
|
||||
//{
|
||||
// var ex = task.Exception;
|
||||
// if (ex != null)
|
||||
// {
|
||||
// System.Diagnostics.Trace.WriteLine(ex.ToString());
|
||||
// Globals.Logger?.Error(ex.ToString());
|
||||
// }
|
||||
//}
|
||||
|
||||
///// <summary>
|
||||
///// Disabling CS4014
|
||||
///// http://stackoverflow.com/questions/22629951/suppressing-warning-cs4014-because-this-call-is-not-awaited-execution-of-the
|
||||
///// warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed.
|
||||
///// Consider applying the 'await' operator to the result of the call.
|
||||
///// </summary>
|
||||
///// <param name="task"></param>
|
||||
//public static void Forget(this Task task)
|
||||
//{
|
||||
// // Async in C# 5.0, pp.57
|
||||
// // Task 를 실행만 하고, await 하지 않는 fire & forget 모델에서, exception 이 발생하였을 경우를 체크 하기 위한 용도.
|
||||
// task.ContinueWith(ant => HandleException(ant));
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// http://stackoverflow.com/questions/2565166/net-best-way-to-execute-a-lambda-on-ui-thread-after-a-delay
|
||||
/// </summary>
|
||||
/// Usage
|
||||
/// <code>
|
||||
/// SynchronizationContext.Current.Post(TimeSpan.FromSeconds(1), () => textBlock.Text="Done");
|
||||
/// </code>
|
||||
public static void Post(this SynchronizationContext context, TimeSpan delay, Action action)
|
||||
{
|
||||
System.Threading.Timer timer = null;
|
||||
|
||||
timer = new System.Threading.Timer((ignore) =>
|
||||
{
|
||||
timer.Dispose();
|
||||
|
||||
context.Post(ignore2 => action(), null);
|
||||
}, null, delay, TimeSpan.FromMilliseconds(-1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes action after delay.
|
||||
/// C# 5.0 in a Nutshell, pp. 573
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
/// <param name="delayMillisec"></param>
|
||||
/// <returns></returns>
|
||||
public static Task ExecuteWithDelay(this Action action, int delayMillisec)
|
||||
{
|
||||
return Task.Delay(delayMillisec).ContinueWith(ant => action);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// pp.20. Concurrency in C# Cookbook
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static Task<T> FromResult<T>(this T value)
|
||||
{
|
||||
return Task.FromResult(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,161 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
|
||||
namespace SystemX.Net.Platform.Common.ExtensionMethods
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// http://stackoverflow.com/questions/2368757/easy-way-to-convert-a-bitmap-and-png-image-to-text-and-vice-versa
|
||||
/// http://www.developerfusion.com/thread/47978/how-can-i-convert-image-type-to-bitmap-type-in-cnet/
|
||||
/// http://stackoverflow.com/questions/10442269/scaling-a-system-drawing-bitmap-to-a-given-size-while-maintaining-aspect-ratio
|
||||
public static class EmBitmap
|
||||
{
|
||||
public static string EncodeToString(this Bitmap bitmap)
|
||||
{
|
||||
if ( bitmap == null )
|
||||
return String.Empty;
|
||||
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
bitmap.Save(memoryStream, ImageFormat.Png);
|
||||
byte[] bitmapBytes = memoryStream.GetBuffer();
|
||||
return Convert.ToBase64String(bitmapBytes, Base64FormattingOptions.InsertLineBreaks);
|
||||
}
|
||||
|
||||
public static Bitmap FromEncodedString(string bitmapString)
|
||||
{
|
||||
byte[] bitmapBytes = Convert.FromBase64String(bitmapString);
|
||||
MemoryStream memoryStream = new MemoryStream(bitmapBytes);
|
||||
return new Bitmap(Image.FromStream(memoryStream));
|
||||
}
|
||||
|
||||
public static Bitmap Resize(this Bitmap bitmap, int width)
|
||||
{
|
||||
double height = width * ((double)bitmap.Height / bitmap.Width);
|
||||
return new Bitmap(bitmap, new Size(width, (int)height));
|
||||
}
|
||||
|
||||
|
||||
public static Icon ToIcon(this Bitmap bitmap)
|
||||
{
|
||||
return Icon.FromHandle(bitmap.GetHicon());
|
||||
}
|
||||
|
||||
public static Bitmap ToBitmap(this Image image)
|
||||
{
|
||||
return (Bitmap) image;
|
||||
}
|
||||
|
||||
public static Icon ToIcon(this Image image)
|
||||
{
|
||||
return Icon.FromHandle(((Bitmap)image).GetHicon());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class ImageHelper
|
||||
{
|
||||
#region CropUnwantedBackground
|
||||
public static Bitmap CropUnwantedBackground(Bitmap bmp)
|
||||
{
|
||||
var backColor = GetMatchedBackColor(bmp);
|
||||
if (backColor.HasValue)
|
||||
{
|
||||
var bounds = GetImageBounds(bmp, backColor);
|
||||
var diffX = bounds[1].X - bounds[0].X + 1;
|
||||
var diffY = bounds[1].Y - bounds[0].Y + 1;
|
||||
var croppedBmp = new Bitmap(diffX, diffY);
|
||||
var g = Graphics.FromImage(croppedBmp);
|
||||
var destRect = new Rectangle(0, 0, croppedBmp.Width, croppedBmp.Height);
|
||||
var srcRect = new Rectangle(bounds[0].X, bounds[0].Y, diffX, diffY);
|
||||
g.DrawImage(bmp, destRect, srcRect, GraphicsUnit.Pixel);
|
||||
return croppedBmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
#region GetImageBounds
|
||||
private static Point[] GetImageBounds(Bitmap bmp, Color? backColor)
|
||||
{
|
||||
//--------------------------------------------------------------------
|
||||
// Finding the Bounds of Crop Area bu using Unsafe Code and Image Proccesing
|
||||
Color c;
|
||||
int width = bmp.Width, height = bmp.Height;
|
||||
bool upperLeftPointFounded = false;
|
||||
var bounds = new Point[2];
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
c = bmp.GetPixel(x, y);
|
||||
bool sameAsBackColor = ((c.R <= backColor.Value.R * 1.1 && c.R >= backColor.Value.R * 0.9) &&
|
||||
(c.G <= backColor.Value.G * 1.1 && c.G >= backColor.Value.G * 0.9) &&
|
||||
(c.B <= backColor.Value.B * 1.1 && c.B >= backColor.Value.B * 0.9));
|
||||
if (!sameAsBackColor)
|
||||
{
|
||||
if (!upperLeftPointFounded)
|
||||
{
|
||||
bounds[0] = new Point(x, y);
|
||||
bounds[1] = new Point(x, y);
|
||||
upperLeftPointFounded = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x > bounds[1].X)
|
||||
bounds[1].X = x;
|
||||
else if (x < bounds[0].X)
|
||||
bounds[0].X = x;
|
||||
if (y >= bounds[1].Y)
|
||||
bounds[1].Y = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bounds;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GetMatchedBackColor
|
||||
private static Color? GetMatchedBackColor(Bitmap bmp)
|
||||
{
|
||||
// Getting The Background Color by checking Corners of Original Image
|
||||
var corners = new Point[]{
|
||||
new Point(0, 0),
|
||||
new Point(0, bmp.Height - 1),
|
||||
new Point(bmp.Width - 1, 0),
|
||||
new Point(bmp.Width - 1, bmp.Height - 1)
|
||||
}; // four corners (Top, Left), (Top, Right), (Bottom, Left), (Bottom, Right)
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
var cornerMatched = 0;
|
||||
var backColor = bmp.GetPixel(corners[i].X, corners[i].Y);
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
var cornerColor = bmp.GetPixel(corners[j].X, corners[j].Y);// Check RGB with some offset
|
||||
if ((cornerColor.R <= backColor.R * 1.1 && cornerColor.R >= backColor.R * 0.9) &&
|
||||
(cornerColor.G <= backColor.G * 1.1 && cornerColor.G >= backColor.G * 0.9) &&
|
||||
(cornerColor.B <= backColor.B * 1.1 && cornerColor.B >= backColor.B * 0.9))
|
||||
{
|
||||
cornerMatched++;
|
||||
}
|
||||
}
|
||||
if (cornerMatched > 2)
|
||||
{
|
||||
return backColor;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Linq;
|
||||
|
||||
namespace SystemX.Net.Platform.Common.ExtensionMethods
|
||||
{
|
||||
public static class EmComparable
|
||||
{
|
||||
/// <summary>
|
||||
/// [min, max]
|
||||
/// value 값이 from, to 사이에 존재하는지를 검사한다.
|
||||
/// http://stackoverflow.com/questions/8776624/if-value-in-rangex-y-function-c-sharp
|
||||
/// </summary>
|
||||
[Pure]
|
||||
public static bool InClosedRange<T>(this T val, T min, T max) where T : IComparable<T>
|
||||
{
|
||||
Contract.Requires(min.CompareTo(max) <= 0);
|
||||
return min.CompareTo(val) <= 0 && val.CompareTo(max) <= 0;
|
||||
}
|
||||
|
||||
[Pure]
|
||||
public static bool InRange<T>(this T val, T min, T max) where T : IComparable<T>
|
||||
{
|
||||
return val.InClosedRange(min, max);
|
||||
}
|
||||
|
||||
/// <summary> [min, max) </summary>
|
||||
[Pure]
|
||||
public static bool InClampRange<T>(this T val, T min, T max) where T : IComparable<T>
|
||||
{
|
||||
Contract.Requires(min.CompareTo(max) <= 0);
|
||||
return min.CompareTo(val) <= 0 && val.CompareTo(max) < 0;
|
||||
}
|
||||
|
||||
/// <summary> (min, max) </summary>
|
||||
[Pure]
|
||||
public static bool InOpenRange<T>(this T val, T min, T max) where T : IComparable<T>
|
||||
{
|
||||
Contract.Requires(min.CompareTo(max) <= 0);
|
||||
return min.CompareTo(val) < 0 && val.CompareTo(max) < 0;
|
||||
}
|
||||
|
||||
|
||||
[Pure]
|
||||
public static bool EpsilonEqual(this double value1, double value2, double epsilon = Double.Epsilon)
|
||||
{
|
||||
return Math.Abs(value1 - value2) < epsilon;
|
||||
}
|
||||
|
||||
[Pure]
|
||||
public static bool EpsilonEqual(this float value1, float value2, float epsilon = Single.Epsilon)
|
||||
{
|
||||
return Math.Abs(value1 - value2) < epsilon;
|
||||
}
|
||||
|
||||
/// <summary> Key 값이 set 에 포함되는지 여부를 검사한다. </summary>
|
||||
[Pure]
|
||||
public static bool IsOneOf(this IComparable key, params IComparable[] set)
|
||||
{
|
||||
return set.Any(e => e.CompareTo(key) == 0);
|
||||
}
|
||||
|
||||
|
||||
public static bool IsOneOf(this object key, params object[] set)
|
||||
{
|
||||
return set.Any(e => e == key);
|
||||
}
|
||||
|
||||
public static bool IsOneOf(this Type type, params Type[] set)
|
||||
{
|
||||
return set.Any(t => t.IsAssignableFrom(type));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,427 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
||||
namespace SystemX.Net.Platform.Common.ExtensionMethods
|
||||
{
|
||||
/// <summary>
|
||||
/// http://lostechies.com/derickbailey/2011/01/24/asynchronous-control-updates-in-c-net-winforms/
|
||||
/// </summary>
|
||||
public static class EmControl
|
||||
{
|
||||
public static void Do<TControl>(this TControl control, Action<TControl> action)
|
||||
where TControl : Control
|
||||
{
|
||||
try
|
||||
{
|
||||
if (control.InvokeRequired)
|
||||
{
|
||||
try
|
||||
{
|
||||
control.Invoke(action, control);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is ObjectDisposedException)
|
||||
Trace.WriteLine(ex);
|
||||
else
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else if (control.IsHandleCreated)
|
||||
action(control);
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Error : Before windows handle created.. 창 핸들을 만들기 전까지는....");
|
||||
Trace.WriteLine("Error : Before windows handle created.. 창 핸들을 만들기 전까지는....");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Trace.WriteLine($"Exception on Control.Do(): {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Control.Invoke is synchronous
|
||||
/// </summary>
|
||||
/// <param name="control"></param>
|
||||
/// <param name="action"></param>
|
||||
public static void Do(this Control control, Action action)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (control.InvokeRequired)
|
||||
{
|
||||
try
|
||||
{
|
||||
control.Invoke(action);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is ObjectDisposedException)
|
||||
Trace.WriteLine(ex);
|
||||
else
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else if (control.IsHandleCreated)
|
||||
action();
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Error : Before windows handle created (2).. 창 핸들을 만들기 전까지는....");
|
||||
Trace.WriteLine("Error : Before windows handle created (2).. 창 핸들을 만들기 전까지는....");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Trace.WriteLine($"Exception on Control.Do(): {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
public static void Do(this SynchronizationContext context, Action action)
|
||||
{
|
||||
context.Send(ignore => { action(); }, null);
|
||||
}
|
||||
public static void DoAsync(this SynchronizationContext context, Action action)
|
||||
{
|
||||
context.Post(ignore => { action(); }, null);
|
||||
}
|
||||
|
||||
public static SynchronizationContext GetSynchronizationContext(this Control control)
|
||||
{
|
||||
SynchronizationContext context = null;
|
||||
control.Do(() =>
|
||||
{
|
||||
context = SynchronizationContext.Current;
|
||||
});
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
public static TaskScheduler GetTaskScheduler(this Control control)
|
||||
{
|
||||
TaskScheduler scheduler = null;
|
||||
control.Do(() =>
|
||||
{
|
||||
scheduler = TaskScheduler.FromCurrentSynchronizationContext();
|
||||
});
|
||||
|
||||
return scheduler;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// form 에 대해서, 아직 창 핸들이 만들어 지지 않은 경우, form 이 보여진 후에 해당 action 을 수행한다.
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <param name="action"></param>
|
||||
public static void DoNowOrLater(this Form form, Action action)
|
||||
{
|
||||
if (form.InvokeRequired)
|
||||
form.Invoke(action);
|
||||
else if (form.IsHandleCreated)
|
||||
action();
|
||||
else
|
||||
form.Shown += (sender, args) => { action(); };
|
||||
}
|
||||
|
||||
public static async Task DoAsync(this Control control, Action action)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (control.InvokeRequired)
|
||||
await Task.Factory.FromAsync(control.BeginInvoke(action), result => { });
|
||||
else if (control.IsHandleCreated)
|
||||
action();
|
||||
else
|
||||
Console.WriteLine("Error : 창 핸들을 만들기 전까지는....");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Trace.WriteLine($"Exception on Control.Do(): {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// How to get return value when BeginInvoke/Invoke is called in C#
|
||||
/// http://stackoverflow.com/questions/2214002/how-to-get-return-value-when-begininvoke-invoke-is-called-in-c-sharp
|
||||
/// </summary>
|
||||
public static T DoGet<T>(this Control control, Func<T> func)
|
||||
{
|
||||
if (control.InvokeRequired)
|
||||
return (T)control.Invoke(func);
|
||||
|
||||
return func();
|
||||
}
|
||||
|
||||
public static IEnumerable<Control> CollectAncestors(this Control control, bool includeMe = false)
|
||||
{
|
||||
if (includeMe)
|
||||
yield return control;
|
||||
if (control == null || control.Parent == null)
|
||||
yield break;
|
||||
|
||||
foreach (var ancestor in control.Parent.CollectAncestors(true))
|
||||
yield return ancestor;
|
||||
}
|
||||
|
||||
public static IEnumerable<Control> CollectAncestorsTo(this Control control, Control stopAncestorControl,
|
||||
bool includeMe = false)
|
||||
{
|
||||
if (includeMe)
|
||||
yield return control;
|
||||
|
||||
if (control == stopAncestorControl || control.Parent == null)
|
||||
yield break;
|
||||
|
||||
foreach (var ancestor in control.Parent.CollectAncestorsTo(stopAncestorControl, true))
|
||||
yield return ancestor;
|
||||
}
|
||||
|
||||
|
||||
public static IEnumerable<Control> CollectChildren(this Control control, bool includeMe = false)
|
||||
{
|
||||
if (includeMe)
|
||||
yield return control;
|
||||
|
||||
foreach (var child in control.Controls.Cast<Control>())
|
||||
{
|
||||
foreach (var descendant in child.CollectChildren(true))
|
||||
yield return descendant;
|
||||
}
|
||||
|
||||
if (control is TabControl)
|
||||
{
|
||||
var tab = (TabControl) control;
|
||||
foreach (var page in tab.TabPages.Cast<TabPage>())
|
||||
{
|
||||
foreach (var descendant in page.CollectChildren(true))
|
||||
{
|
||||
yield return descendant;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static IEnumerable<T> CollectChildren<T>(this Control control, bool includeMe = false) where T : Control
|
||||
{
|
||||
return control.CollectChildren(includeMe).OfType<T>();
|
||||
|
||||
//if (includeMe && control is T)
|
||||
// yield return control as T;
|
||||
|
||||
//foreach (var child in control.Controls.Cast<Control>())
|
||||
//{
|
||||
// foreach (var descendant in child.CollectChildren<T>(true))
|
||||
// yield return descendant;
|
||||
//}
|
||||
|
||||
//if (control is TabControl)
|
||||
//{
|
||||
// var tab = (TabControl)control;
|
||||
// foreach (var page in tab.TabPages.Cast<TabPage>())
|
||||
// {
|
||||
// foreach (var descendant in page.CollectChildren<T>(true))
|
||||
// {
|
||||
// yield return descendant;
|
||||
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// reference 의 LT 좌표 기준으로, control 의 LT 좌표의 offset 값을 반환한다.
|
||||
/// </summary>
|
||||
/// <param name="control"></param>
|
||||
/// <param name="reference"></param>
|
||||
/// <returns></returns>
|
||||
public static Point GetRelativePoint(this Control control, Control reference)
|
||||
{
|
||||
return reference.PointToClient(control.PointToScreen(control.Location));
|
||||
}
|
||||
|
||||
public static Rectangle GetRelativeRectangle(this Control control, Control reference)
|
||||
{
|
||||
return reference.RectangleToClient(control.RectangleToScreen(control.ClientRectangle));
|
||||
}
|
||||
|
||||
public static void SetBackgroundImage(this Control control, Image image)
|
||||
{
|
||||
if (control.BackgroundImage != null)
|
||||
control.BackgroundImage.Dispose();
|
||||
|
||||
control.BackgroundImage = image;
|
||||
}
|
||||
|
||||
public static void MakeTransparent(this Control control)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (control is Button)
|
||||
((Button) control).FlatStyle = FlatStyle.Flat;
|
||||
|
||||
control.ForceMakeTransparent();
|
||||
control.BackColor = Color.Transparent;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// http://solvedstack.com/questions/transparency-for-windows-forms-textbox
|
||||
/// <c>
|
||||
/// bool itWorked = SetStyle(xControl, ControlStyles.SupportsTransparentBackColor, true);
|
||||
/// </c>
|
||||
/// </summary>
|
||||
/// <param name="control"></param>
|
||||
/// <param name="style"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static bool ForceSetStyle(this Control control, ControlStyles style, bool value)
|
||||
{
|
||||
Type typeTB = typeof (Control);
|
||||
System.Reflection.MethodInfo misSetStyle = typeTB.GetMethod("SetStyle",
|
||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||
if (misSetStyle != null && control != null)
|
||||
{
|
||||
misSetStyle.Invoke(control, new object[] {style, value});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ForceMakeTransparent(this Control control, bool transparent = true)
|
||||
{
|
||||
return control.ForceSetStyle(ControlStyles.SupportsTransparentBackColor, transparent);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// http://stackoverflow.com/questions/435433/what-is-the-preferred-way-to-find-focused-control-in-winforms-app
|
||||
/// </summary>
|
||||
/// <param name="control"></param>
|
||||
/// <returns></returns>
|
||||
public static Control FindFocusedControl(this Control control)
|
||||
{
|
||||
var container = control as IContainerControl;
|
||||
while (container != null)
|
||||
{
|
||||
control = container.ActiveControl;
|
||||
container = control as IContainerControl;
|
||||
}
|
||||
return control;
|
||||
}
|
||||
|
||||
|
||||
// http://stackoverflow.com/questions/4747935/c-sharp-winform-check-if-control-is-physicaly-visible
|
||||
[DllImport("user32.dll")]
|
||||
static extern IntPtr WindowFromPoint(POINT Point);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct POINT
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
|
||||
public POINT(int x, int y) { X = x; Y = y; }
|
||||
public static implicit operator Point(POINT p) => new Point(p.X, p.Y);
|
||||
public static implicit operator POINT(Point p) => new POINT(p.X, p.Y);
|
||||
}
|
||||
|
||||
/// control 이 실제로 사용자에게 보이는지 여부를 반환
|
||||
public static bool IsControlVisibleToUser(this Control control)
|
||||
{
|
||||
return control.DoGet(() =>
|
||||
{
|
||||
if (!control.IsHandleCreated)
|
||||
return false;
|
||||
|
||||
var pos = control.PointToScreen(control.Location);
|
||||
var pointsToCheck = new POINT[] {
|
||||
pos,
|
||||
new Point(pos.X + control.Width - 1, pos.Y),
|
||||
new Point(pos.X, pos.Y + control.Height - 1),
|
||||
new Point(pos.X + control.Width - 1, pos.Y + control.Height - 1),
|
||||
new Point(pos.X + control.Width/2, pos.Y + control.Height/2),
|
||||
};
|
||||
|
||||
foreach (var p in pointsToCheck)
|
||||
{
|
||||
var hwnd = WindowFromPoint(p);
|
||||
var other = Control.FromChildHandle(hwnd);
|
||||
if (other == null)
|
||||
continue;
|
||||
|
||||
if (control == other || control.Contains(other))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
#region Detect cursor
|
||||
//// http://stackoverflow.com/questions/586479/is-there-a-quick-way-to-get-the-control-thats-under-the-mouse
|
||||
//[DllImport("user32.dll")]
|
||||
//private static extern IntPtr WindowFromPoint(Point pnt);
|
||||
|
||||
//public static Control ControlUnderPoint(this Point pt)
|
||||
//{
|
||||
// IntPtr hWnd = WindowFromPoint(pt);
|
||||
// if (hWnd != IntPtr.Zero)
|
||||
// return Control.FromHandle(hWnd);
|
||||
|
||||
// return null;
|
||||
//}
|
||||
|
||||
//public static Control ControlUnderMouseCursor()
|
||||
//{
|
||||
// return Control.MousePosition.ControlUnderPoint();
|
||||
//}
|
||||
|
||||
/// <summary> Checks whether mouse is over given control </summary>
|
||||
public static bool IsMouseOver(this Control control)
|
||||
{
|
||||
return control.ClientRectangle.Contains(control.PointToClient(Cursor.Position));
|
||||
}
|
||||
|
||||
/// <summary> Collects controls under mouse cursor </summary>
|
||||
public static IEnumerable<Control> GetChildrenUnderMouse(this Control parent)
|
||||
{
|
||||
foreach (var c in parent.Controls.Cast<Control>())
|
||||
{
|
||||
if (c.IsMouseOver())
|
||||
yield return c;
|
||||
foreach (var cc in GetChildrenUnderMouse(c))
|
||||
yield return cc;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
/// Button 에 image 를 입힌다. text 는 왼쪽, image 는 오른쪽
|
||||
public static void AddImage(this Button button, Image image)
|
||||
{
|
||||
button.Image = image;
|
||||
button.ImageAlign = ContentAlignment.MiddleRight;
|
||||
button.TextAlign = ContentAlignment.MiddleLeft;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
using System;
|
||||
|
||||
namespace SystemX.Net.Platform.Common.ExtensionMethods
|
||||
{
|
||||
public static class EmEventHandler
|
||||
{
|
||||
public static void Handle(this EventHandler eventHandler, object sender, EventArgs eventArgs)
|
||||
{
|
||||
var handler = eventHandler;
|
||||
if (handler != null)
|
||||
handler(sender, eventArgs);
|
||||
}
|
||||
|
||||
public static void Handle<T>(this EventHandler<T> eventHandler, object sender, T eventArgs)
|
||||
{
|
||||
var handler = eventHandler;
|
||||
if ( handler != null )
|
||||
handler(sender, eventArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,133 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace SystemX.Net.Platform.Common.ExtensionMethods
|
||||
{
|
||||
public static class EmGeneral
|
||||
{
|
||||
/// <summary>Indicates whether the specified array is null or has a length of zero.</summary>
|
||||
/// <param name="array">The array to test.</param>
|
||||
/// <returns>true if the array parameter is null or has a length of zero; otherwise, false.</returns>
|
||||
[Pure]
|
||||
public static bool IsNullOrEmpty(this Array array)
|
||||
{
|
||||
return (array == null || array.Length == 0);
|
||||
}
|
||||
|
||||
|
||||
[Pure]
|
||||
public static bool IsNullOrEmpty(this IEnumerable enumerable)
|
||||
{
|
||||
return (enumerable == null || enumerable.Cast<object>().Count() == 0);
|
||||
}
|
||||
|
||||
[Pure]
|
||||
public static bool NonNullAny<TSource>(this IEnumerable<TSource> source)
|
||||
{
|
||||
if (source == null)
|
||||
return false;
|
||||
return source.Any();
|
||||
}
|
||||
|
||||
[Pure]
|
||||
public static bool NonNullAny<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
|
||||
{
|
||||
if (source == null)
|
||||
return false;
|
||||
return source.Any(predicate);
|
||||
}
|
||||
|
||||
[Pure]
|
||||
public static int Clamp(this int val, int min, int max)
|
||||
{
|
||||
return val > max ? max : val < min ? min : val;
|
||||
}
|
||||
|
||||
public static double Clamp(this double val, double min, double max)
|
||||
{
|
||||
return val > max ? max : val < min ? min : val;
|
||||
}
|
||||
|
||||
[Pure]
|
||||
public static bool XOR(this bool val1, bool val2)
|
||||
{
|
||||
return (val1 && !val2) || (!val1 && val2);
|
||||
}
|
||||
|
||||
[Pure]
|
||||
public static bool XOR(this object obj1, object obj2)
|
||||
{
|
||||
return (obj1 != null && obj2 == null) || (obj1 == null && obj2 != null);
|
||||
}
|
||||
|
||||
[Pure]
|
||||
public static bool Toggle(this bool fact, bool toggle)
|
||||
{
|
||||
return toggle ? ! fact : fact;
|
||||
}
|
||||
|
||||
[Pure]
|
||||
public static string NonNullEmptySelector(this string str1, string str2)
|
||||
{
|
||||
return String.IsNullOrEmpty(str1) ? str2 : str1;
|
||||
}
|
||||
|
||||
|
||||
[Pure]
|
||||
public static bool NonNullEqual(this string str1, string str2)
|
||||
{
|
||||
return !String.IsNullOrEmpty(str1) && !String.IsNullOrEmpty(str2) && str1 == str2;
|
||||
}
|
||||
|
||||
[Pure]
|
||||
public static bool NullableEqual(this string str1, string str2)
|
||||
{
|
||||
return (str1.IsNullOrEmpty() && str2.IsNullOrEmpty()) || NonNullEqual(str1, str2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static bool HasTrueValue(this Nullable<bool> nullable)
|
||||
{
|
||||
return nullable.HasValue && nullable.Value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// http://stackoverflow.com/questions/12447156/how-can-i-set-the-column-width-of-a-property-grid
|
||||
/// </summary>
|
||||
public static class PropertyGridColumnWidthSetter
|
||||
{
|
||||
public static void SetLabelColumnWidth(this PropertyGrid grid, int width)
|
||||
{
|
||||
if (grid == null)
|
||||
return;
|
||||
|
||||
FieldInfo fi = grid.GetType().GetField("gridView", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (fi == null)
|
||||
return;
|
||||
|
||||
Control view = fi.GetValue(grid) as Control;
|
||||
if (view == null)
|
||||
return;
|
||||
|
||||
MethodInfo mi = view.GetType().GetMethod("MoveSplitterTo", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (mi == null)
|
||||
return;
|
||||
mi.Invoke(view, new object[] {width});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,374 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace SystemX.Net.Platform.Common.ExtensionMethods
|
||||
{
|
||||
/// <summary>
|
||||
/// Linq extension methods
|
||||
/// </summary>
|
||||
public static partial class EmLinq
|
||||
{
|
||||
// http://stackoverflow.com/questions/1883920/call-a-function-for-each-value-in-a-generic-c-sharp-collection
|
||||
/// <summary>
|
||||
/// Generic IEnumerable ForEach extension : typename T is optional. deducible from source
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="action"></param>
|
||||
|
||||
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
|
||||
{
|
||||
foreach (T item in source)
|
||||
action(item);
|
||||
}
|
||||
|
||||
public static void Iter<T>(this IEnumerable<T> source, Action<T> action) => ForEach(source, action);
|
||||
public static void Iter<T>(this IEnumerable<T> source, Action<T, int> action)
|
||||
{
|
||||
int i = 0;
|
||||
foreach (T item in source)
|
||||
action(item, i++);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lazy Foreach : Not evaluated until on demand
|
||||
/// </summary>
|
||||
public static IEnumerable<T> ForEachTee<T>(this IEnumerable<T> source, Action<T> action)
|
||||
{
|
||||
foreach (T item in source)
|
||||
{
|
||||
action(item);
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Non-Generic IEnumerable ForEach extension : typename T should be provided.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="action"></param>
|
||||
public static void ForEach<T>(this IEnumerable source, Action<T> action)
|
||||
{
|
||||
foreach (T item in source)
|
||||
action(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Non-Generic IEnumerable ForEach extension : typename T should be provided.
|
||||
/// Lazy Foreach : Not evaluated until on demand
|
||||
/// </summary>
|
||||
public static IEnumerable ForEachTee<T>(this IEnumerable source, Action<T> action)
|
||||
{
|
||||
foreach (T item in source)
|
||||
{
|
||||
action(item);
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Non-Generic IEnumerable Select extension : typename T should be provided.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource"></typeparam>
|
||||
/// <typeparam name="TResult"></typeparam>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="selector"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<TResult> SelectEx<TSource, TResult>(this IEnumerable source, Func<TSource, TResult> selector)
|
||||
{
|
||||
foreach (TSource item in source)
|
||||
yield return selector(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TResult type 의 enumerable 중에서 TNotCheckType type 이 아닌 것들만 골라서 반환한다. (System.Linq.OfType 의 negation)
|
||||
/// <para/> System.Linq.SkipWhile() 구문과 같은 역할
|
||||
/// <para/> TNotCheck 는 TResult type 이어야 함.
|
||||
/// </summary>
|
||||
/// <typeparam name="TResult">enumerable 들의 base type. 동시에 반환될 enumerable 의 type</typeparam>
|
||||
/// <typeparam name="TNotCheckType">제외할 type</typeparam>
|
||||
/// <param name="source"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<TResult> OfNotType<TResult, TNotCheckType>(this IEnumerable source) where TNotCheckType : TResult
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
return OfNotTypeIterator<TResult, TNotCheckType>(source);
|
||||
}
|
||||
|
||||
|
||||
private static IEnumerable<TResult> OfNotTypeIterator<TResult, TNotCheckType>(IEnumerable source)
|
||||
{
|
||||
foreach (object obj in source)
|
||||
{
|
||||
if (!(obj is TNotCheckType))
|
||||
yield return (TResult)obj;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Select Non null element from enumerable
|
||||
/// </summary>
|
||||
public static IEnumerable<TResult> OfNotNull<TResult>(this IEnumerable<TResult> source) where TResult : class
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
foreach (var s in source)
|
||||
{
|
||||
if ( s != null )
|
||||
yield return s;
|
||||
}
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/2471588/how-to-get-index-using-linq
|
||||
public static Nullable<int> FindIndex<T>(this IEnumerable<T> items, Predicate<T> predicate)
|
||||
{
|
||||
int index = 0;
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (predicate(item))
|
||||
return index;
|
||||
index++;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static HashSet<T> ToHashSet<T>(this IEnumerable<T> items)
|
||||
{
|
||||
var hash = new HashSet<T>();
|
||||
items.ForEach(i => hash.Add(i));
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 두개의 set 이 동일한지 비교. see SequenceEqual
|
||||
/// </summary>
|
||||
public static bool SetEqual<T>(this IEnumerable<T> first, IEnumerable<T> second)
|
||||
{
|
||||
HashSet<T> firstSet = first.ToHashSet();
|
||||
foreach (var e in second)
|
||||
{
|
||||
if (!firstSet.Contains(e))
|
||||
return false;
|
||||
}
|
||||
|
||||
HashSet<T> secondSet = second.ToHashSet();
|
||||
foreach (var e in first)
|
||||
{
|
||||
if (!secondSet.Contains(e))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static bool RemoveTail(this IList list)
|
||||
{
|
||||
if (list.IsNullOrEmpty())
|
||||
return false;
|
||||
|
||||
list.RemoveAt(list.Count - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static T[] ConcatArrays<T>(params T[][] list)
|
||||
{
|
||||
var result = new T[list.Sum(a => a.Length)];
|
||||
int offset = 0;
|
||||
for (int x = 0; x < list.Length; x++)
|
||||
{
|
||||
list[x].CopyTo(result, offset);
|
||||
offset += list[x].Length;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private static Tuple<bool, T> ExtractFirst<T>(this IEnumerable<T> seq)
|
||||
{
|
||||
using (var enumerator = seq.GetEnumerator())
|
||||
{
|
||||
if (enumerator.MoveNext())
|
||||
return Tuple.Create(true, enumerator.Current); // => return new Tuple<bool, T>(..) 와 동일
|
||||
|
||||
return Tuple.Create(false, default(T));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// http://stackoverflow.com/questions/4354902/check-that-all-items-of-ienumerablet-has-the-same-value-using-linq
|
||||
/// </summary>
|
||||
public static bool AllEqual<T>(this IEnumerable<T> source, T target)
|
||||
{
|
||||
using (var enumerator = source.GetEnumerator())
|
||||
{
|
||||
if (!enumerator.MoveNext())
|
||||
{
|
||||
// empty case
|
||||
return true;
|
||||
}
|
||||
|
||||
var comparer = EqualityComparer<T>.Default;
|
||||
|
||||
do
|
||||
{
|
||||
if (!comparer.Equals(target, enumerator.Current))
|
||||
return false;
|
||||
} while (enumerator.MoveNext());
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool AllEqual<T>(this IEnumerable<T> source)
|
||||
{
|
||||
var pr = source.ExtractFirst();
|
||||
if (pr.Item1)
|
||||
return AllEqual(source, pr.Item2);
|
||||
|
||||
// empty case
|
||||
return true;
|
||||
}
|
||||
|
||||
public static T Tee<T>(this T input, Action action)
|
||||
{
|
||||
action();
|
||||
return input;
|
||||
}
|
||||
public static T Tee<T>(this T input, Action<T> action)
|
||||
{
|
||||
action(input);
|
||||
return input;
|
||||
}
|
||||
|
||||
public static bool ForAll<T>(this IEnumerable<T> source, Func<T, bool> predicate)
|
||||
{
|
||||
foreach (var s in source)
|
||||
{
|
||||
if (!predicate(s))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ForAll<T>(this IEnumerable<T> source, Func<T, int, bool> predicate)
|
||||
{
|
||||
int i = 0;
|
||||
foreach (var s in source)
|
||||
{
|
||||
if (!predicate(s, i++))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static bool NoForAll<T>(this IEnumerable<T> source, Func<T, bool> predicate)
|
||||
{
|
||||
foreach (var s in source)
|
||||
{
|
||||
if (predicate(s))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// source 를 n 개씩 분할한 sequence 를 반환
|
||||
/// http://stackoverflow.com/questions/419019/split-list-into-sublists-with-linq
|
||||
/// </summary>
|
||||
public static IEnumerable<IEnumerable<T>> SplitByN<T>(this IEnumerable<T> source, int n)
|
||||
{
|
||||
return source
|
||||
.Select((x, i) => new { Index = i, Value = x })
|
||||
.GroupBy(x => x.Index / n)
|
||||
.Select(x => x.Select(v => v.Value))
|
||||
;
|
||||
}
|
||||
|
||||
public static IEnumerable<T> EveryNth<T>(this IEnumerable<T> source, int n)
|
||||
{
|
||||
return source.Where((v, i) => i % n == 0);
|
||||
}
|
||||
|
||||
|
||||
public static IEnumerable<TResult> Zip2<TS1, TS2, TResult>(
|
||||
this IEnumerable<TS1> s1,
|
||||
IEnumerable<TS2> s2,
|
||||
Func<TS1, TS2, TResult> resultSelector) => s1.Zip(s2, resultSelector);
|
||||
|
||||
public static IEnumerable<TResult> Zip3<TS1, TS2, TS3, TResult>(
|
||||
this IEnumerable<TS1> s1,
|
||||
IEnumerable<TS2> s2,
|
||||
IEnumerable<TS3> s3,
|
||||
Func<TS1, TS2, TS3, TResult> resultSelector)
|
||||
{
|
||||
using (var e1 = s1.GetEnumerator())
|
||||
using (var e2 = s2.GetEnumerator())
|
||||
using (var e3 = s3.GetEnumerator())
|
||||
{
|
||||
while (e1.MoveNext() && e2.MoveNext() && e3.MoveNext())
|
||||
yield return resultSelector(e1.Current, e2.Current, e3.Current);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<TResult> Zip4<TS1, TS2, TS3, TS4, TResult>(
|
||||
this IEnumerable<TS1> s1,
|
||||
IEnumerable<TS2> s2,
|
||||
IEnumerable<TS3> s3,
|
||||
IEnumerable<TS4> s4,
|
||||
Func<TS1, TS2, TS3, TS4, TResult> resultSelector)
|
||||
{
|
||||
using (var e1 = s1.GetEnumerator())
|
||||
using (var e2 = s2.GetEnumerator())
|
||||
using (var e3 = s3.GetEnumerator())
|
||||
using (var e4 = s4.GetEnumerator())
|
||||
{
|
||||
while (e1.MoveNext() && e2.MoveNext() && e3.MoveNext() && e4.MoveNext())
|
||||
yield return resultSelector(e1.Current, e2.Current, e3.Current, e4.Current);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static IEnumerable<int> MinMaxRange(int min, int hop, int max)
|
||||
{
|
||||
if (hop <= 0)
|
||||
throw new ArgumentException("hop counter should be positive.");
|
||||
|
||||
for (int i = min; i <= max; i += hop)
|
||||
yield return i;
|
||||
}
|
||||
|
||||
public static IEnumerable<int> MinMaxRange(int min, int max) => Enumerable.Range(min, max - min);
|
||||
|
||||
public static IEnumerable<string> HexRange(int start, int count)
|
||||
{
|
||||
foreach (var h in Enumerable.Range(start, count))
|
||||
{
|
||||
yield return $"{h:X}";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Enumerable 의 laziness 를 강제로 실행시켜 evaluation 시킴.
|
||||
/// </summary>
|
||||
public static IEnumerable<T> Realize<T>(this IEnumerable<T> seq)
|
||||
{
|
||||
//var count = seq.Count(); // count 만으로는, 즉석 evaluation 이 안되는 경우가 존재...???...
|
||||
var array = seq.ToArray();
|
||||
return array;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user