using System;
using System.Reflection;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
public class Test
{
class MyClass<T> {
public void MyMethod(T a, List<T> b, List<KeyValuePair<T, string>> c) {}
}
public static void Main() {
var typesAsStr = new [] {"T", "List`1[T]", "List`1[KeyValuePair`2[T, string]]"};
var myMethods = typeof(MyClass<>)
.GetMethods()
.Where(m => m.Name == "MyMethod")
.ToList();
MethodInfo myMethod = null;
foreach (var candidate in myMethods) {
var paramTypes = candidate.GetParameters().Select(m => m.ParameterType).ToArray();
bool allGood = paramTypes.Length == typesAsStr.Length;
for (var i = 0 ; allGood && i != paramTypes.Length ; i++) {
allGood &= MatchType(typesAsStr[i], paramTypes[i]);
}
if (allGood) {
myMethod = candidate;
break;
}
}
Console.WriteLine("'{0}'", myMethod);
}
private enum TokenType {
OpenBraket,
CloseBraket,
Comma,
Tick,
Identifier,
Number
}
private class Token {
public TokenType Type { get; private set; }
public string Text { get; private set; }
public Token(TokenType type, string text) {
Type = type;
Text = text;
}
public override string ToString() {
return string.Format("{0}:{1}", Enum.GetName(typeof(TokenType), Type), Text);
}
}
private static bool DropToken(Queue<Token> tokens, TokenType expected) {
return (tokens.Count != 0) && (tokens.Dequeue().Type == expected);
}
private static bool ReadToken(Queue<Token> tokens, TokenType expected, out string text) {
var res = (tokens.Count != 0) && (tokens.Peek().Type == expected);
text = res ? tokens.Dequeue().Text : null;
return res;
}
private static IEnumerable<Token> Tokenize(IEnumerable<char> str) {
var res = new List<Token>();
var text = new StringBuilder();
foreach (var c in str) {
var pos = "[],`".IndexOf(c);
if ((pos != -1 || char.IsWhiteSpace(c)) && text.Length != 0) {
res.Add(new Token(
char.IsDigit(text[0]) ? TokenType.Number : TokenType.Identifier
, text.ToString())
);
text = new StringBuilder();
}
if (pos != -1) {
res.Add(new Token((TokenType)pos, c.ToString(CultureInfo.InvariantCulture)));
} else if (!char.IsWhiteSpace(c)) {
text.Append(c);
}
}
if (text.Length != 0) {
res.Add(new Token(
char.IsDigit(text[0]) ? TokenType.Number : TokenType.Identifier
, text.ToString())
);
}
return res;
}
public static bool MatchType(string str, Type type) {
var queue = new Queue<Token>(Tokenize(str));
return MatchRecursive(queue, type) && (queue.Count == 0);
}
private static bool MatchRecursive(Queue<Token> tokens, Type type) {
string baseName;
if (!ReadToken(tokens, TokenType.Identifier, out baseName)) return false;
var ranks = new List<int>();
while (type.IsArray) {
ranks.Add(type.GetArrayRank());
type = type.GetElementType();
}
if (type.IsGenericType) {
if (!type.Name.StartsWith(baseName+"`") || !DropToken(tokens, TokenType.Tick)) return false;
string numStr;
int num;
if (!ReadToken(tokens, TokenType.Number, out numStr)
|| !int.TryParse(numStr, out num)
|| !DropToken(tokens, TokenType.OpenBraket)) return false;
var genParams = type.GetGenericArguments();
if (genParams.Length != num) return false;
for (var i = 0 ; i < num ; i++) {
if (i != 0 && !DropToken(tokens, TokenType.Comma)) return false;
if (!MatchRecursive(tokens, genParams[i])) return false;
}
if (!DropToken(tokens, TokenType.CloseBraket)) return false;
}
foreach (var rank in ranks) {
if (!DropToken(tokens, TokenType.OpenBraket)) return false;
for (var i = 0 ; i != rank-1 ; i++) {
if (!DropToken(tokens, TokenType.Comma)) return false;
}
if (!DropToken(tokens, TokenType.CloseBraket)) return false;
}
return type.IsGenericType || Aliases.Contains(new KeyValuePair<string, Type>(baseName, type)) || type.Name == baseName;
}
private static readonly HashSet<KeyValuePair<string,Type>> Aliases = new HashSet<KeyValuePair<string, Type>> {
new KeyValuePair<string, Type>("bool", typeof(bool)),
new KeyValuePair<string, Type>("byte", typeof(byte)),
new KeyValuePair<string, Type>("sbyte", typeof(sbyte)),
new KeyValuePair<string, Type>("char", typeof(char)),
new KeyValuePair<string, Type>("string", typeof(string)),
new KeyValuePair<string, Type>("short", typeof(short)),
new KeyValuePair<string, Type>("ushort", typeof(ushort)),
new KeyValuePair<string, Type>("int", typeof(int)),
new KeyValuePair<string, Type>("uint", typeof(uint)),
new KeyValuePair<string, Type>("long", typeof(long)),
new KeyValuePair<string, Type>("ulong", typeof(ulong)),
new KeyValuePair<string, Type>("float", typeof(float)),
new KeyValuePair<string, Type>("double", typeof(double)),
new KeyValuePair<string, Type>("decimal", typeof(decimal)),
new KeyValuePair<string, Type>("void", typeof(void)),
new KeyValuePair<string, Type>("object", typeof(object))
};
}
dXNpbmcgU3lzdGVtOwp1c2luZyBTeXN0ZW0uUmVmbGVjdGlvbjsKdXNpbmcgU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWM7CnVzaW5nIFN5c3RlbS5HbG9iYWxpemF0aW9uOwp1c2luZyBTeXN0ZW0uTGlucTsKdXNpbmcgU3lzdGVtLlRleHQ7CgpwdWJsaWMgY2xhc3MgVGVzdAp7CiAgICBjbGFzcyBNeUNsYXNzPFQ+IHsKICAgICAgICBwdWJsaWMgdm9pZCBNeU1ldGhvZChUIGEsIExpc3Q8VD4gYiwgTGlzdDxLZXlWYWx1ZVBhaXI8VCwgc3RyaW5nPj4gYykge30KICAgIH0KCiAgICBwdWJsaWMgc3RhdGljIHZvaWQgTWFpbigpIHsKICAgICAgICB2YXIgdHlwZXNBc1N0ciA9IG5ldyBbXSB7IlQiLCAiTGlzdGAxW1RdIiwgIkxpc3RgMVtLZXlWYWx1ZVBhaXJgMltULCBzdHJpbmddXSJ9OwogICAgICAgIHZhciBteU1ldGhvZHMgPSB0eXBlb2YoTXlDbGFzczw+KQogICAgICAgICAgICAuR2V0TWV0aG9kcygpCiAgICAgICAgICAgIC5XaGVyZShtID0+IG0uTmFtZSA9PSAiTXlNZXRob2QiKQogICAgICAgICAgICAuVG9MaXN0KCk7CiAgICAgICAgTWV0aG9kSW5mbyBteU1ldGhvZCA9IG51bGw7CiAgICAgICAgZm9yZWFjaCAodmFyIGNhbmRpZGF0ZSBpbiBteU1ldGhvZHMpIHsKICAgICAgICAgICAgdmFyIHBhcmFtVHlwZXMgPSBjYW5kaWRhdGUuR2V0UGFyYW1ldGVycygpLlNlbGVjdChtID0+IG0uUGFyYW1ldGVyVHlwZSkuVG9BcnJheSgpOwogICAgICAgICAgICBib29sIGFsbEdvb2QgPSBwYXJhbVR5cGVzLkxlbmd0aCA9PSB0eXBlc0FzU3RyLkxlbmd0aDsKICAgICAgICAgICAgZm9yICh2YXIgaSA9IDAgOyBhbGxHb29kICYmIGkgIT0gcGFyYW1UeXBlcy5MZW5ndGggOyBpKyspIHsKICAgICAgICAgICAgICAgIGFsbEdvb2QgJj0gTWF0Y2hUeXBlKHR5cGVzQXNTdHJbaV0sIHBhcmFtVHlwZXNbaV0pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChhbGxHb29kKSB7CiAgICAgICAgICAgICAgICBteU1ldGhvZCA9IGNhbmRpZGF0ZTsKICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIENvbnNvbGUuV3JpdGVMaW5lKCInezB9JyIsIG15TWV0aG9kKTsKICAgIH0KCiAgICBwcml2YXRlIGVudW0gVG9rZW5UeXBlIHsKICAgICAgICBPcGVuQnJha2V0LAogICAgICAgIENsb3NlQnJha2V0LAogICAgICAgIENvbW1hLAogICAgICAgIFRpY2ssCiAgICAgICAgSWRlbnRpZmllciwKICAgICAgICBOdW1iZXIKICAgIH0KICAgIHByaXZhdGUgY2xhc3MgVG9rZW4gewogICAgICAgIHB1YmxpYyBUb2tlblR5cGUgVHlwZSB7IGdldDsgcHJpdmF0ZSBzZXQ7IH0KICAgICAgICBwdWJsaWMgc3RyaW5nIFRleHQgeyBnZXQ7IHByaXZhdGUgc2V0OyB9CiAgICAgICAgcHVibGljIFRva2VuKFRva2VuVHlwZSB0eXBlLCBzdHJpbmcgdGV4dCkgewogICAgICAgICAgICBUeXBlID0gdHlwZTsKICAgICAgICAgICAgVGV4dCA9IHRleHQ7CiAgICAgICAgfQogICAgICAgIHB1YmxpYyBvdmVycmlkZSBzdHJpbmcgVG9TdHJpbmcoKSB7CiAgICAgICAgICAgIHJldHVybiBzdHJpbmcuRm9ybWF0KCJ7MH06ezF9IiwgRW51bS5HZXROYW1lKHR5cGVvZihUb2tlblR5cGUpLCBUeXBlKSwgVGV4dCk7CiAgICAgICAgfQogICAgfQogICAgcHJpdmF0ZSBzdGF0aWMgYm9vbCBEcm9wVG9rZW4oUXVldWU8VG9rZW4+IHRva2VucywgVG9rZW5UeXBlIGV4cGVjdGVkKSB7CiAgICAgICAgcmV0dXJuICh0b2tlbnMuQ291bnQgIT0gMCkgJiYgKHRva2Vucy5EZXF1ZXVlKCkuVHlwZSA9PSBleHBlY3RlZCk7CiAgICB9CiAgICBwcml2YXRlIHN0YXRpYyBib29sIFJlYWRUb2tlbihRdWV1ZTxUb2tlbj4gdG9rZW5zLCBUb2tlblR5cGUgZXhwZWN0ZWQsIG91dCBzdHJpbmcgdGV4dCkgewogICAgICAgIHZhciByZXMgPSAodG9rZW5zLkNvdW50ICE9IDApICYmICh0b2tlbnMuUGVlaygpLlR5cGUgPT0gZXhwZWN0ZWQpOwogICAgICAgIHRleHQgPSByZXMgPyB0b2tlbnMuRGVxdWV1ZSgpLlRleHQgOiBudWxsOwogICAgICAgIHJldHVybiByZXM7CiAgICB9CiAgICBwcml2YXRlIHN0YXRpYyBJRW51bWVyYWJsZTxUb2tlbj4gVG9rZW5pemUoSUVudW1lcmFibGU8Y2hhcj4gc3RyKSB7CiAgICAgICAgdmFyIHJlcyA9IG5ldyBMaXN0PFRva2VuPigpOwogICAgICAgIHZhciB0ZXh0ID0gbmV3IFN0cmluZ0J1aWxkZXIoKTsKICAgICAgICBmb3JlYWNoICh2YXIgYyBpbiBzdHIpIHsKICAgICAgICAgICAgdmFyIHBvcyA9ICJbXSxgIi5JbmRleE9mKGMpOwogICAgICAgICAgICBpZiAoKHBvcyAhPSAtMSB8fCBjaGFyLklzV2hpdGVTcGFjZShjKSkgJiYgdGV4dC5MZW5ndGggIT0gMCkgewogICAgICAgICAgICAgICAgcmVzLkFkZChuZXcgVG9rZW4oCiAgICAgICAgICAgICAgICAgICAgY2hhci5Jc0RpZ2l0KHRleHRbMF0pID8gVG9rZW5UeXBlLk51bWJlciA6IFRva2VuVHlwZS5JZGVudGlmaWVyCiAgICAgICAgICAgICAgICAsICAgdGV4dC5Ub1N0cmluZygpKQogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICAgIHRleHQgPSBuZXcgU3RyaW5nQnVpbGRlcigpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChwb3MgIT0gLTEpIHsKICAgICAgICAgICAgICAgIHJlcy5BZGQobmV3IFRva2VuKChUb2tlblR5cGUpcG9zLCBjLlRvU3RyaW5nKEN1bHR1cmVJbmZvLkludmFyaWFudEN1bHR1cmUpKSk7CiAgICAgICAgICAgIH0gZWxzZSBpZiAoIWNoYXIuSXNXaGl0ZVNwYWNlKGMpKSB7CiAgICAgICAgICAgICAgICB0ZXh0LkFwcGVuZChjKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZiAodGV4dC5MZW5ndGggIT0gMCkgewogICAgICAgICAgICByZXMuQWRkKG5ldyBUb2tlbigKICAgICAgICAgICAgICAgIGNoYXIuSXNEaWdpdCh0ZXh0WzBdKSA/IFRva2VuVHlwZS5OdW1iZXIgOiBUb2tlblR5cGUuSWRlbnRpZmllcgogICAgICAgICAgICAsICAgdGV4dC5Ub1N0cmluZygpKQogICAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcmVzOwogICAgfQogICAgcHVibGljIHN0YXRpYyBib29sIE1hdGNoVHlwZShzdHJpbmcgc3RyLCBUeXBlIHR5cGUpIHsKICAgICAgICB2YXIgcXVldWUgPSBuZXcgUXVldWU8VG9rZW4+KFRva2VuaXplKHN0cikpOwogICAgICAgIHJldHVybiBNYXRjaFJlY3Vyc2l2ZShxdWV1ZSwgdHlwZSkgJiYgKHF1ZXVlLkNvdW50ID09IDApOwogICAgfQogICAgcHJpdmF0ZSBzdGF0aWMgYm9vbCBNYXRjaFJlY3Vyc2l2ZShRdWV1ZTxUb2tlbj4gdG9rZW5zLCBUeXBlIHR5cGUpIHsKICAgICAgICBzdHJpbmcgYmFzZU5hbWU7CiAgICAgICAgaWYgKCFSZWFkVG9rZW4odG9rZW5zLCBUb2tlblR5cGUuSWRlbnRpZmllciwgb3V0IGJhc2VOYW1lKSkgcmV0dXJuIGZhbHNlOwogICAgICAgIHZhciByYW5rcyA9IG5ldyBMaXN0PGludD4oKTsKICAgICAgICB3aGlsZSAodHlwZS5Jc0FycmF5KSB7CiAgICAgICAgICAgIHJhbmtzLkFkZCh0eXBlLkdldEFycmF5UmFuaygpKTsKICAgICAgICAgICAgdHlwZSA9IHR5cGUuR2V0RWxlbWVudFR5cGUoKTsKICAgICAgICB9CiAgICAgICAgaWYgKHR5cGUuSXNHZW5lcmljVHlwZSkgewogICAgICAgICAgICBpZiAoIXR5cGUuTmFtZS5TdGFydHNXaXRoKGJhc2VOYW1lKyJgIikgfHwgIURyb3BUb2tlbih0b2tlbnMsIFRva2VuVHlwZS5UaWNrKSkgcmV0dXJuIGZhbHNlOwogICAgICAgICAgICBzdHJpbmcgbnVtU3RyOwogICAgICAgICAgICBpbnQgbnVtOwogICAgICAgICAgICBpZiAoIVJlYWRUb2tlbih0b2tlbnMsIFRva2VuVHlwZS5OdW1iZXIsIG91dCBudW1TdHIpCiAgICAgICAgICAgIHx8ICAhaW50LlRyeVBhcnNlKG51bVN0ciwgb3V0IG51bSkKICAgICAgICAgICAgfHwgICFEcm9wVG9rZW4odG9rZW5zLCBUb2tlblR5cGUuT3BlbkJyYWtldCkpIHJldHVybiBmYWxzZTsKICAgICAgICAgICAgdmFyIGdlblBhcmFtcyA9IHR5cGUuR2V0R2VuZXJpY0FyZ3VtZW50cygpOwogICAgICAgICAgICBpZiAoZ2VuUGFyYW1zLkxlbmd0aCAhPSBudW0pIHJldHVybiBmYWxzZTsKICAgICAgICAgICAgZm9yICh2YXIgaSA9IDAgOyBpIDwgbnVtIDsgaSsrKSB7CiAgICAgICAgICAgICAgICBpZiAoaSAhPSAwICYmICFEcm9wVG9rZW4odG9rZW5zLCBUb2tlblR5cGUuQ29tbWEpKSByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgICAgICBpZiAoIU1hdGNoUmVjdXJzaXZlKHRva2VucywgZ2VuUGFyYW1zW2ldKSkgcmV0dXJuIGZhbHNlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICghRHJvcFRva2VuKHRva2VucywgVG9rZW5UeXBlLkNsb3NlQnJha2V0KSkgcmV0dXJuIGZhbHNlOwogICAgICAgIH0KICAgICAgICBmb3JlYWNoICh2YXIgcmFuayBpbiByYW5rcykgewogICAgICAgICAgICBpZiAoIURyb3BUb2tlbih0b2tlbnMsIFRva2VuVHlwZS5PcGVuQnJha2V0KSkgcmV0dXJuIGZhbHNlOwogICAgICAgICAgICBmb3IgKHZhciBpID0gMCA7IGkgIT0gcmFuay0xIDsgaSsrKSB7CiAgICAgICAgICAgICAgICBpZiAoIURyb3BUb2tlbih0b2tlbnMsIFRva2VuVHlwZS5Db21tYSkpIHJldHVybiBmYWxzZTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoIURyb3BUb2tlbih0b2tlbnMsIFRva2VuVHlwZS5DbG9zZUJyYWtldCkpIHJldHVybiBmYWxzZTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHR5cGUuSXNHZW5lcmljVHlwZSB8fCBBbGlhc2VzLkNvbnRhaW5zKG5ldyBLZXlWYWx1ZVBhaXI8c3RyaW5nLCBUeXBlPihiYXNlTmFtZSwgdHlwZSkpIHx8IHR5cGUuTmFtZSA9PSBiYXNlTmFtZTsKICAgIH0KICAgIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IEhhc2hTZXQ8S2V5VmFsdWVQYWlyPHN0cmluZyxUeXBlPj4gQWxpYXNlcyA9IG5ldyBIYXNoU2V0PEtleVZhbHVlUGFpcjxzdHJpbmcsIFR5cGU+PiB7CiAgICAgICAgbmV3IEtleVZhbHVlUGFpcjxzdHJpbmcsIFR5cGU+KCJib29sIiwgdHlwZW9mKGJvb2wpKSwKICAgICAgICBuZXcgS2V5VmFsdWVQYWlyPHN0cmluZywgVHlwZT4oImJ5dGUiLCB0eXBlb2YoYnl0ZSkpLAogICAgICAgIG5ldyBLZXlWYWx1ZVBhaXI8c3RyaW5nLCBUeXBlPigic2J5dGUiLCB0eXBlb2Yoc2J5dGUpKSwKICAgICAgICBuZXcgS2V5VmFsdWVQYWlyPHN0cmluZywgVHlwZT4oImNoYXIiLCB0eXBlb2YoY2hhcikpLAogICAgICAgIG5ldyBLZXlWYWx1ZVBhaXI8c3RyaW5nLCBUeXBlPigic3RyaW5nIiwgdHlwZW9mKHN0cmluZykpLAogICAgICAgIG5ldyBLZXlWYWx1ZVBhaXI8c3RyaW5nLCBUeXBlPigic2hvcnQiLCB0eXBlb2Yoc2hvcnQpKSwKICAgICAgICBuZXcgS2V5VmFsdWVQYWlyPHN0cmluZywgVHlwZT4oInVzaG9ydCIsIHR5cGVvZih1c2hvcnQpKSwKICAgICAgICBuZXcgS2V5VmFsdWVQYWlyPHN0cmluZywgVHlwZT4oImludCIsIHR5cGVvZihpbnQpKSwKICAgICAgICBuZXcgS2V5VmFsdWVQYWlyPHN0cmluZywgVHlwZT4oInVpbnQiLCB0eXBlb2YodWludCkpLAogICAgICAgIG5ldyBLZXlWYWx1ZVBhaXI8c3RyaW5nLCBUeXBlPigibG9uZyIsIHR5cGVvZihsb25nKSksCiAgICAgICAgbmV3IEtleVZhbHVlUGFpcjxzdHJpbmcsIFR5cGU+KCJ1bG9uZyIsIHR5cGVvZih1bG9uZykpLAogICAgICAgIG5ldyBLZXlWYWx1ZVBhaXI8c3RyaW5nLCBUeXBlPigiZmxvYXQiLCB0eXBlb2YoZmxvYXQpKSwKICAgICAgICBuZXcgS2V5VmFsdWVQYWlyPHN0cmluZywgVHlwZT4oImRvdWJsZSIsIHR5cGVvZihkb3VibGUpKSwKICAgICAgICBuZXcgS2V5VmFsdWVQYWlyPHN0cmluZywgVHlwZT4oImRlY2ltYWwiLCB0eXBlb2YoZGVjaW1hbCkpLAogICAgICAgIG5ldyBLZXlWYWx1ZVBhaXI8c3RyaW5nLCBUeXBlPigidm9pZCIsIHR5cGVvZih2b2lkKSksCiAgICAgICAgbmV3IEtleVZhbHVlUGFpcjxzdHJpbmcsIFR5cGU+KCJvYmplY3QiLCB0eXBlb2Yob2JqZWN0KSkKICAgIH07Cn0=