-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTypeLike.cs
More file actions
147 lines (133 loc) · 5.55 KB
/
TypeLike.cs
File metadata and controls
147 lines (133 loc) · 5.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
using System;
using System.ComponentModel;
using System.Reflection;
using LangExt;
namespace ReflectionExt
{
/// <summary>
/// 型を表す実装を共有するためのクラスです。
/// </summary>
public abstract class TypeLike
{
/// <summary>
/// このオブジェクトが表す型です。
/// </summary>
protected readonly Type Type;
/// <summary>
/// 保持する型を指定してオブジェクトを構築します。
/// </summary>
protected TypeLike(Type type)
{
this.Type = type;
}
/// <summary>
/// オブジェクトをSystem.Typeに変換します。
/// </summary>
public Type ToType()
{
return this.Type;
}
/// <summary>
/// このオブジェクトの表す型の名前を取得します。
/// </summary>
public Name Name { get { return Name.FromType(this.Type); } }
}
/// <summary>
/// 型を表す実装を共有するためのクラスです。
/// </summary>
/// <typeparam name="TSelf">派生クラス自身を指定してください。</typeparam>
public abstract class TypeLike<TSelf> : TypeLike, IEquatable<TSelf> where TSelf : TypeLike<TSelf>
{
/// <summary>
/// 保持する型を指定してオブジェクトを構築します。
/// </summary>
protected TypeLike(Type type) : base(type) { }
protected abstract TSelf ToSelf(Type rawType);
/// <summary>
/// 基底クラスを取得します。
/// </summary>
public TSelf BaseType { get { return ToSelf(this.Type.BaseType); } }
/// <summary>
/// このオブジェクトの表す型に直接含まれるネストした型をすべて取得します。
/// </summary>
public Seq<TSelf> AllNestedTypes
{
get { return this.Type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic).Map(this.ToSelf).ToSeq(); }
}
/// <summary>
/// このオブジェクトの表す型に直接含まれるネストしたpublicな型を取得します。
/// 非publicな型も含めて取得したい場合、AllNestedTypesを使用してください。
/// </summary>
public Seq<TSelf> PublicNestedTypes
{
get { return this.Type.GetNestedTypes(BindingFlags.Public).Map(this.ToSelf).ToSeq(); }
}
protected static Seq<Type> TypeArgs(Type type, Seq<TSelf> typeParameterTypes, Func<Type, Seq<TSelf>, TSelf> fromTypeFunc)
{
var offset = 0;
return type.GetGenericArguments().ToSeq().Map(t =>
{
if (t.IsGenericParameter)
{
if (offset + 1 > typeParameterTypes.Size())
throw new ArgumentException();
return LangExt.Unsafe.SeqUnsafe.Get(typeParameterTypes, offset++).ToType();
}
if (t.IsGenericTypeDefinition)
{
var count = CountOfTypeParameterTypes(t);
if (offset + count > typeParameterTypes.Size())
throw new ArgumentException();
var res = fromTypeFunc(t, typeParameterTypes.Skip(offset).Take(count));
offset += count;
return res.ToType();
}
return t;
});
}
static int CountOfTypeParameterTypes(Type type)
{
if (type.ContainsGenericParameters == false)
return 0;
var nested = type.GetGenericArguments();
var count = nested.ToSeq().Count(t => t.IsGenericParameter);
return count + nested.ToSeq().SumBy(CountOfTypeParameterTypes);
}
/// <summary>
/// 現在のオブジェクトが、同じ型の別のオブジェクトと等しいかどうかを判定します。
/// </summary>
/// <param name="other">このオブジェクトと比較するTSelf</param>
/// <returns>現在のオブジェクトがotherで指定されたオブジェクトと等しい場合はtrue、それ以外の場合はfalse</returns>
public bool Equals(TSelf other)
{
return this.Name.CSharpFullName == other.Name.CSharpFullName;
}
/// <summary>
/// このオブジェクトを文字列表現に変換します。
/// </summary>
/// <returns>このオブジェクトの文字列表現</returns>
public override string ToString()
{
return string.Format("{0}(value={1})", this.GetType().Name, this.Name.CSharpFullName);
}
/// <summary>
/// 現在のオブジェクトが、別のオブジェクトと等しいかどうかを判定します。
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public override bool Equals(object obj)
{
var other = obj as TSelf;
if (other == null)
return false;
return this.Equals(other);
}
/// <summary>
/// 現在のオブジェクトのハッシュ値を計算して返します。
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public override int GetHashCode()
{
return this.Name.GetHashCode();
}
}
}