Общие конструкторы и отражение

Это звучит как ошибка регрессии, так как о ней сообщалось / исправлялось несколько раз.

У меня есть похожая тема здесь на SO: Xamarin.Forms ViewModelLocator вызывается дважды

Не устанавливайте BindingContext в XAML, если это не приложение на одну страницу вместо этого рассмотрите возможность использования контейнера IoC.

9
задан tanascius 15 May 2009 в 16:00
поделиться

4 ответа

Вам нужен System.Reflection.ParameterInfo.ParameterType.IsGenericParameter. Вот проходной модульный тест VS2008, который иллюстрирует это:

Класс:

public class Foo<T>
{
    public Foo(T val)
    {
        this.Value = val.ToString();
    }
    public Foo(string val)
    {
        this.Value = "--" + val + "--";
    }

    public string Value { get; set; }
}

Метод тестирования:

Foo<string> f = new Foo<string>("hello");
Assert.AreEqual("--hello--", f.Value);

Foo<int> g = new Foo<int>(10);
Assert.AreEqual("10", g.Value);

Type t = typeof(Foo<string>);
t = t.GetGenericTypeDefinition();

Assert.AreEqual(2, t.GetConstructors().Length);

System.Reflection.ConstructorInfo c = t.GetConstructors()[0];
System.Reflection.ParameterInfo[] parms = c.GetParameters();
Assert.AreEqual(1, parms.Length);
Assert.IsTrue(parms[0].ParameterType.IsGenericParameter);

c = t.GetConstructors()[1];
parms = c.GetParameters();
Assert.AreEqual(1, parms.Length);
Assert.IsFalse(parms[0].ParameterType.IsGenericParameter);

Примечательным моментом здесь является проверка parms [0] .ParameterType.IsGenericParameter, которая проверяет, является ли параметр универсальным или нет .

После того, как вы нашли свой конструктор, у вас есть ConstructorInfo для передачи в Emit.

public System.Reflection.ConstructorInfo FindStringConstructor(Type t)
{
    Type t2 = t.GetGenericTypeDefinition();

    System.Reflection.ConstructorInfo[] cs = t2.GetConstructors();
    for (int i = 0; i < cs.Length; i++)
    {
        if (cs[i].GetParameters()[0].ParameterType == typeof(string))
        {
            return t.GetConstructors()[i];
        }
    }

    return null;
}

Не совсем уверен, каковы ваши намерения.

8
ответ дан 4 December 2019 в 21:11
поделиться

Небольшое уточнение. Ни один из конструкторов не является универсальными методами. Это обычные методы универсального класса. Чтобы метод был «универсальным», он должен иметь универсальный параметр. Таким образом, выполнение теста типа «IsGenericMethod» вернет false.

Также непросто просто посмотреть на параметры и определить, являются ли они общими. В примере, который вы предоставили, можно пройтись по аргументам и найти общий параметр. Но также рассмотрите следующий код

public Foo(IEnumerable<T> p1) ...
public Foo(IEnumerable<KeyValuePair<string,Func<T>>> p1) ...

. Вам нужно будет принять во внимание такие элементы.

EDIT

Причина, по которой вы видите все аргументы как строку, заключается в том, что вы явно связали тип Foo перед получением конструкторов , Попробуйте переключить свой код на следующий, который использует несвязанный Foo и, следовательно, будет возвращать общие параметры в методах.

var constructors = typeof( Foo<> ).GetConstructors();
2
ответ дан 4 December 2019 в 21:11
поделиться

Вы можете проверить тип (ы) результатов Type.GetGenericArguments и сравнить его с типом параметра конструктора.

Просто вызовите тот, у которого есть тип не то же самое (type! = typeof (T)).

0
ответ дан 4 December 2019 в 21:11
поделиться

Не могли бы вы подробнее объяснить, чего вы пытаетесь достичь, когда говорите, что хотите вызвать конкретный конструктор? Мне просто интересно, есть ли другой способ решить вашу проблему без необходимости определять, содержит ли конструктор общие параметры.

Я подумываю объединить конструкторы в цепочку или встроить логику в общий, чтобы они вели себя определенным образом, если переданный параметр является строкой, например:

    static void Main(string[] args)
    {
        Console.WriteLine(new Foo<string>("myValue").IsValueAString);
        Console.WriteLine(new Foo<int>(1).IsValueAString);
        Console.ReadLine();
    }

    public class Foo<T>
    {
        public bool IsValueAString = false;
        public Foo(T value) {
            if (value is string)
            {
                IsValueAString = true;
            }
        }
    }

Другой вариант - создать конкретную реализацию Foo, что-то вроде :

internal class Foo<T>
{
    ...
}
internal class MyFoo : Foo<string>
{
    ...
}

и встроить любую конкретную логику в конструктор потомка. На этом пути возможны всевозможные варианты, поэтому вам не придется отображать информацию из этого одного класса.

0
ответ дан 4 December 2019 в 21:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: