Как получить доступ к универсальному свойству, не зная закрытого универсального типа - PullRequest
13 голосов
/ 04 января 2011

У меня есть общий тип следующим образом

public class TestGeneric<T>
{
    public T Data { get; set; }
    public TestGeneric(T data)
    {
        this.Data = data;
    }
}

Если у меня теперь есть объект (который поступает из какого-то внешнего источника), из которого я знаю, что его тип имеет какой-то закрытый TestGeneric <>, но я не знаю TypeParameter T. Теперь мне нужен доступ к данным моего объекта. Проблема в том, что я не могу привести объект, так как не знаю точно, к какому закрытому TestGeneric.

Я использую

// thx to /381108/proverte-yavlyaetsya-li-klass-proizvodnym-ot-universalnogo-klassa
private static bool IsSubclassOfRawGeneric(Type rawGeneric, Type subclass)
{
    while (subclass != typeof(object))
    {
        var cur = subclass.IsGenericType ? subclass.GetGenericTypeDefinition() : subclass;
        if (rawGeneric == cur)
        {
            return true;
        }
        subclass = subclass.BaseType;
    }
    return false;
}

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

public static void Main()
{
    object myObject = new TestGeneric<string>("test"); // or from another source
    if (IsSubclassOfRawGeneric(typeof(TestGeneric<>), myObject.GetType()))
    {
        // the following gives an InvalidCastException
        // var data = ((TestGeneric<object>)myObject).Data;

        // if i try to access the property with reflection
        // i get an InvalidOperationException
        var dataProperty = typeof(TestGeneric<>).GetProperty("Data");
        object data = dataProperty.GetValue(myObject, new object[] { });
    }
}

Мне нужны Данные независимо от их типа (ну, если бы я мог запросить их тип, используя GetType (), это было бы хорошо, но не обязательно), так как я просто хочу вывести их в xml, используя ToString ().

Есть предложения? Thanx.

Ответы [ 4 ]

28 голосов
/ 12 января 2011

О, стеки ... почему никто не указал мне на тип dynamic ??Это идеальный пример использования, который делает код ОЧЕНЬ более читабельным:

dynamic dynObject = myObject;
object data = dynObject.Data;
12 голосов
/ 04 января 2011

Вам необходимо знать закрытый тип универсального класса, прежде чем вы сможете получить доступ к его универсальным членам.Использование TestGeneric<> дает определение открытого типа, которое не может быть вызвано без указания общих аргументов.

Самый простой способ получить значение свойства - отразить используемый тип закрытого типа.напрямую:

public static void Main()
{
    object myObject = new TestGeneric<string>("test"); // or from another source

    var type = myObject.GetType();

    if (IsSubclassOfRawGeneric(typeof(TestGeneric<>), type))
    {
        var dataProperty = type.GetProperty("Data");
        object data = dataProperty.GetValue(myObject, new object[] { });
    }
}
4 голосов
/ 04 января 2011

Аа, простите за это.Это была простая ошибка, универсальная версия работает, конечно, она должна читать

var dataProperty = myObject.GetType().GetProperty("Data");
object data = dataProperty.GetValue(myObject, new object[] { });
1 голос
/ 27 июня 2018

С C # 6 и выше мы можем использовать nameof, чтобы немного улучшить ответ Павла:

public static void Main()
{
    object myObject = new TestGeneric<string>("test"); // or from another source

    var type = myObject.GetType();

    if (IsSubclassOfRawGeneric(typeof(TestGeneric<>), type))
    {
        var dataProperty = type.GetProperty(nameof(TestGeneric<object>.Data));
        object data = dataProperty.GetValue(myObject);
    }
}

Обратите внимание, что замена type.GetProperty("Data") на type.GetProperty(nameof(TestGeneric<object>.Data)) обеспечивает безопасность времени компиляции (что, вероятно, лучше, чем использование способа dynamic).

Также использование object в качестве параметра типа является просто способом получить доступ к свойству и не имеет побочных эффектов или особого значения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...