Skip to content

Instantly share code, notes, and snippets.

@ufcpp
Last active March 29, 2018 11:00
Show Gist options
  • Save ufcpp/b4b505077f589235afb169652e10ee8d to your computer and use it in GitHub Desktop.
Save ufcpp/b4b505077f589235afb169652e10ee8d to your computer and use it in GitHub Desktop.
C# 7.3触り出してみてる
using System;
using System.Linq;
namespace ConsoleApp1Preview
{
class Program
{
static void Main(string[] args)
{
ConstraintOverload();
new Program().StaticOverload();
ReturnOverload();
ExpressoinVariables();
StackallocInitializer();
GenericConstraints();
TupleEquality();
RefReassignment();
}
private static void ConstraintOverload()
{
// これは前からOK。static M(T, int) が呼ばれる。
M(new Disposable(), 0);
// これは C# 7.3 から。M(T, long) の方に行く。
// ジェネリック型制約を先に見るようになった。
M(new Comparable(), 0);
}
struct Disposable : IDisposable { public void Dispose() { } }
struct Comparable : IComparable { public int CompareTo(object obj) => 0; }
static void M<T>(T x, int i) where T : IDisposable => Console.WriteLine("IDisposable");
static void M<T>(T x, long i) where T : IComparable => Console.WriteLine("IComparable");
void StaticOverload()
{
// これは前からOK。static M(string) が呼ばれる。
M("abc");
// これは C# 7.3 から。M(object) の方に行く。
// this. を元に候補を絞る作業が先に入るようになった
this.M("abc");
}
static void M(string x) => Console.WriteLine("static");
void M(object x) => Console.WriteLine("instance");
static void ReturnOverload()
{
// メソッド直渡しだとどっちの M か判別できなかった
// C# 7.3 で、M(Func<int, int>) に絞れるように
M(X);
// ちなみに、ラムダ式を使うと昔からちゃんと判別できてた
M(x => X(x));
}
static int X(int x) => x;
static void M(Func<int, int> f) => Console.WriteLine("int => int");
static void M(Func<int, bool> f) => Console.WriteLine("int => bool");
class ThisInitializer
{
// Dictionary.TryGetValue の方がサンプルとしてよさげかも
public ThisInitializer(string s) : this(int.TryParse(s, out var x) ? x : 0) { }
public ThisInitializer(int len) => Console.WriteLine(len);
}
class FieldInitializer
{
public int X = int.TryParse("123", out var x) ? x : 0;
}
class Base
{
protected Base(out int x) => x = 999;
}
class Derived : Base
{
public Derived()
: base(out var x) // base 初期化子中で out var 宣言した変数は、
=> Console.WriteLine(x); // コンストラクター body で使える
}
static void ExpressoinVariables()
{
var ti = new ThisInitializer("123");
var fi = new FieldInitializer();
Console.WriteLine(fi.X);
var q =
from s in new[] { "a", "1", "abc", "123" }
where int.TryParse(s, out var x) && x > 100
select int.TryParse(s, out var x) ? x : 0;
foreach (var x in q)
{
Console.WriteLine(x);
}
new Derived();
}
// 3/28時点のビルドではまだ merge されてない。というかほんとに7.3に入るのかわかんない
//unsafe struct Buffer8
//{
// public fixed byte Buffer[8];
//}
//static Buffer8 buffer;
//unsafe static void FixedWithoutPinning()
//{
// buffer.Buffer[0] = 1;
//}
private static void StackallocInitializer()
{
Span<int> x0 = stackalloc int[5];
Span<int> x1 = stackalloc int[5] { 1, 2, 3, 4, 5 };
Span<int> x2 = stackalloc int[] { 1, 2, 3, 4, 5 };
Span<int> x3 = stackalloc[] { 1, 2, 3, 4, 5 };
for (int i = 0; i < 5; i++)
{
Console.WriteLine((x0[i], x1[i], x2[i], x3[i]));
}
}
// 3/20時点のビルドではまだ merge されてない
//static void PatternBasedFixed(ref Span<int> x)
//{
// unsafe
// {
// fixed (int* p = x)
// {
// }
// }
//}
struct UnmanagedStruct
{
public int X;
public bool Y;
public short Z;
public override string ToString() => (X, Y, Z).ToString();
}
static void GenericConstraints()
{
EnumConstraint(Color.Red | Color.Blue, Color.Blue);
Console.WriteLine(DelegateConstraint<Func<int, int>>(n => n * n, new object[] { 5 }));
var x = new UnmanagedStruct
{
X = 1,
Y = true,
Z = 2,
};
Console.WriteLine(x);
UnmanagedConstraint(ref x);
Console.WriteLine(x);
}
[Flags]
enum Color
{
Red = 1,
Green = 2,
Blue = 4,
}
static void EnumConstraint<T>(T x, T y)
where T : Enum
{
Console.WriteLine(x.HasFlag(y));
}
static object DelegateConstraint<T>(T d, object[] args)
where T : Delegate
{
// 引数の型まで制約に付けれないから結局 DynamicInvoke…
return d.DynamicInvoke(args);
}
unsafe static void UnmanagedConstraint<T>(ref T x)
where T : unmanaged
{
fixed (T* px = &x)
{
var p = (byte*)px;
var size = sizeof(T);
for (int i = 0; i < size; i++)
{
p[i] = 0;
}
}
}
class AutoProp
{
[field: NonSerialized]
public int X { get; set; }
}
struct MyBool
{
public bool Value;
public MyBool(bool value) => Value = value;
public static bool operator true(MyBool x) { Console.WriteLine("MyBool.true"); return x.Value; }
public static bool operator false(MyBool x) { Console.WriteLine("MyBool.false"); return !x.Value; }
public static implicit operator MyBool(bool b) => new MyBool(b);
}
struct MyInt
{
public int Value;
public MyInt(int value) => Value = value;
public static MyBool operator ==(MyInt x, MyInt y) => x.Value == y.Value;
public static MyBool operator !=(MyInt x, MyInt y) => x.Value != y.Value;
public static implicit operator MyInt(int b) => new MyInt(b);
public override bool Equals(object obj) => obj is MyInt x && Value == x.Value;
public override int GetHashCode() => Value.GetHashCode();
}
private static void TupleEquality()
{
(int, int, int?) x = (1, 2, null);
byte by = 2;
Console.WriteLine(x == (1L, by, null));
var y = (1, (2, 3));
Console.WriteLine(y == (1, (2, 3)));
MyInt a = 1;
MyInt b = 2;
Console.WriteLine((a, b) == (1, 2));
}
private static void RefReassignment()
{
int x = 1;
ref var r = ref x;
int y = 2;
r = ref y;
r = 3;
Console.WriteLine((x, y));
int i = 0;
for (ref var ri = ref i; ri < 10; ri++)
{
//↓これは書けちゃう
//ri = ref y;
}
// 将来の予定? もう行ける?
// foreach (ref var x in ...)
var a = new[] { 1, 2, 3, 4, 5 };
var e = new RefArrayEnumerable<int>(a);
foreach (ref var item in e) item = 0;
foreach (var item in a) Console.WriteLine(item);
//↓ これは C# 7.3 でも認めてない。ref じゃないときも、ループ変数が上書き不能なので
//foreach (ref var item in e) item = ref y;
}
struct RefArrayEnumerable<T>
{
T[] _array;
public RefArrayEnumerable(T[] array) => _array = array;
public RefArrayEnumerator<T> GetEnumerator() => new RefArrayEnumerator<T>(_array);
}
struct RefArrayEnumerator<T>
{
int _index;
T[] _array;
public RefArrayEnumerator(T[] array) => (_index, _array) = (-1, array);
public ref T Current => ref _array[_index];
public bool MoveNext() => ++_index < _array.Length;
}
}
}
using System;
using System.Collections.Generic;
namespace MagicallyResolvedOverload
{
/// <summary>
/// これまで、class だったら T、struct だったら T? を返す、みたいな処理書けなかったんだけど。
/// ちょっと無理やりだけど、C# 7.3 でできなくはない状態に。
/// </summary>
public static class EnumerableEx
{
// 「完全に型制約(where)違いだけのオーバーロード」は作れないんだけど、
// ダミーの引数を用意してやれば…
public struct ClassConstraints { }
public struct StructConstraints { }
/// <summary>
/// クラス用。T で、null を返す。
/// 第3引数にダミーの<see cref="ClassConstraints"/>を取ることで、無理やり構造体版と弁別。
/// </summary>
public static T FirstOrNull<T>(this IEnumerable<T> source, Func<T, bool> predicate, ClassConstraints _ = default)
where T : class
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (predicate == null) throw new ArgumentNullException(nameof(predicate));
foreach (var item in source)
{
if (predicate(item)) return item;
}
return null;
}
/// <summary>
/// 構造体用。T? で、null を返す。
/// 第3引数にダミーの<see cref="StructConstraints"/>を取ることで、無理やりクラス版と弁別。
/// </summary>
public static T? FirstOrNull<T>(this IEnumerable<T> source, Func<T, bool> predicate, StructConstraints _ = default)
where T : struct
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (predicate == null) throw new ArgumentNullException(nameof(predicate));
foreach (var item in source)
{
if (predicate(item)) return item;
}
return null;
}
}
public class Program
{
static void Main()
{
// ちゃんと呼び分けできているか確認
// 構造体版が呼ばれてる。
// 第3引数は = default が効いてて、呼び出し側では未指定で大丈夫。
var a = new[] { 1, 2, 3, 4, 5 };
Console.WriteLine(a.FirstOrNull(x => (x % 2) == 0));
Console.WriteLine(a.FirstOrNull(x => x > 10));
// クラス版が呼ばれてる。
// 第3引数は = default が効いてて、呼び出し側では未指定で大丈夫。
var b = new[] { "", "a", "ab", "abc" };
Console.WriteLine(b.FirstOrNull(x => x.Length > 2));
Console.WriteLine(b.FirstOrNull(x => x == null));
// この無意味なダミー引数を消そうと思ったら .NET の型システム自体に手を入れないと無理なはず?
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
namespace MagicallyResolvedOverload
{
/// <summary>
/// これまで、class だったら T、struct だったら T? を返す、みたいな処理書けなかったんだけど。
/// ちょっと無理やりだけど、C# 7.3 でできなくはない状態に。
/// </summary>
public static class EnumerableForClass
{
/// <summary>
/// クラス用。T で、null を返す。
/// </summary>
public static T FirstOrNull<T>(this IEnumerable<T> source, Func<T, bool> predicate)
where T : class
=> source.FirstOrDefault(predicate);
}
public static class EnumerableForStruct
{
/// <summary>
/// 構造体用。T? で、null を返す。
/// </summary>
public static T? FirstOrNull<T>(this IEnumerable<T> source, Func<T, bool> predicate)
where T : struct
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (predicate == null) throw new ArgumentNullException(nameof(predicate));
foreach (var item in source)
{
if (predicate(item)) return item;
}
return null;
}
}
public class Program
{
static void Main()
{
// ちゃんと呼び分けできているか確認
// 構造体版が呼ばれてる。
// 第3引数は = default が効いてて、呼び出し側では未指定で大丈夫。
var a = new[] { 1, 2, 3, 4, 5 };
Console.WriteLine(a.FirstOrNull(x => (x % 2) == 0));
Console.WriteLine(a.FirstOrNull(x => x > 10));
// クラス版が呼ばれてる。
// 第3引数は = default が効いてて、呼び出し側では未指定で大丈夫。
var b = new[] { "", "a", "ab", "abc" };
Console.WriteLine(b.FirstOrNull(x => x.Length > 2));
Console.WriteLine(b.FirstOrNull(x => x == null));
// この無意味なダミー引数を消そうと思ったら .NET の型システム自体に手を入れないと無理なはず?
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment