Last active
March 29, 2018 11:00
-
-
Save ufcpp/b4b505077f589235afb169652e10ee8d to your computer and use it in GitHub Desktop.
C# 7.3触り出してみてる
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 の型システム自体に手を入れないと無理なはず? | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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