Как перегрузить универсальный IEnumerable - PullRequest
0 голосов
/ 06 июля 2019

Я понимаю, что это распространенная проблема - пытаться перегрузить один универсальный шаблон и универсальный массив. Все эти ответы говорят о том, почему это работает таким образом и как существуют лучшие способы сделать это, но ни один из них не показывает это. Я ищу предложения о том, как добиться того, чего я добиваюсь, и я открыт для рефакторинга, и я делаю это по-другому

Вот код, который представляет проблему: https://dotnetfiddle.net/sWrNj3

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;

public static class MyParser
{
    public static void Parse<T>(string name, T value)
    {
        Console.WriteLine($"{name}: single");
    }

    // Must take in IEnumerable<T>
    public static void Parse<T>(string name, IEnumerable<T> collection)
    {
        Console.WriteLine($"{name}: IEnumerable");
    }

    public static void ParseObj<T>(T data)
    {
        foreach (var prop in data.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
        {
            Parse(prop.Name, prop.GetValue(data, null));
        }
    }
}

public class Program
{
    public static void Main()
    {
        MyParser.ParseObj(new
        {
            Str = "abc", 
            Num = 543, 
            Arr = new[]{1, 2, 3}, 
            Chars = new char[]{'x', 'y', 'z'}}
        );
    }
}

Итог:

Str: single
Num: single
Arr: single
Chars: single

Желаемая:

Str: single
Num: single
Arr: IEnumerable
Chars: IEnumerable

1 Ответ

0 голосов
/ 06 июля 2019

Я думаю, что у вас есть вся необходимая информация, но вы не можете делегировать всю эту работу компилятору, вы должны выполнить эту работу самостоятельно:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using static System.Console;

public static class MyParser
{
    public static void ParseObj<T>(T data)
    {
        foreach (var prop in data.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
        {
            if(prop.PropertyType.IsArray) WriteLine($"{prop.Name}:array");
            else if(prop.PropertyType == (typeof(string))) WriteLine($"{prop.Name}:string");
            else if(prop.PropertyType.IsValueType) WriteLine($"{prop.Name}:value type");
            else if(typeof(IEnumerable).IsAssignableFrom(prop.PropertyType)) WriteLine($"{prop.Name}:IEnumerable");
            else if(prop.PropertyType.IsEnum) WriteLine($"{prop.Name}:enum");
            else if(prop.PropertyType.IsClass) WriteLine($"{prop.Name}:class");
            else WriteLine($"{prop.Name}:something else");
        }
    }
}

public class Program
{
    public static void Main()
    {
        MyParser.ParseObj(new
        {
            Str = "abc"
            , Num = 543
            , Arr = new[]{1, 2, 3}
            , Chars = new char[]{'x', 'y', 'z'}
            , SomeList = new List<string>(){"a","b","c"}
        });
    }
}

выход:

Str:string
Num:value type
Arr:array
Chars:array
SomeList:IEnumerable

* ОБНОВЛЕНИЕ * Добавление эволюции кода к ответу из комментариев на случай, если кто-то еще посчитает этот вопрос полезным:

  1. https://dotnetfiddle.net/Zkx7UJ
  2. https://dotnetfiddle.net/aeCG3z
  3. https://dotnetfiddle.net/6Z49ta
  4. https://dotnetfiddle.net/u5HAFP
...