Использование nameof для свойства рекурсивного универсального типа

У меня есть следующий класс

public abstract class Result<TResult, TData> where TResult : Result<TResult, TData>
{
    public virtual TData Data { get; private set; }
}

Как я могу использовать nameof для свойства Data?

Он пробовал некоторые варианты, но получил ошибки компиляции

nameof(Result<object, object>.Data)

Error   CS0311  
The type 'object' cannot be used as type parameter 'TResult' in the generic type or method 
'Result<TResult, TData>'. There is no implicit reference conversion from 'object' to 
'Result<object, object>'

ОБНОВЛЕНИЕ Чтобы уточнить:

Я не писал класс в первом фрагменте, но я должен использовать его как есть. Мне нужно использовать отражение, чтобы получить экземпляр PropertyInfo для свойства Data. Я могу сделать это, вызвав GetProperty(Data), но я предпочитаю избегать строк, если свойство name переименовывается с помощью рефакторинга Visual Studio (например, из Data в Content). Я не могу использовать nameof(Data) и нахожусь в другом контексте, который не знает о свойстве Data в этом классе.

Таким образом, я бы назвал GetProperty(nameof({whatever}.Data)). Конечно, если бы это было невозможно, я бы использовал строку. Но если есть способ, я хотел бы знать его.


person Franco Tiveron    schedule 18.09.2020    source источник
comment
Это похоже на проблему XY (meta.stackexchange. com/questions/66377/what-is-the-xy-problem)? Какую строку вы надеетесь сгенерировать и почему?   -  person mjwills    schedule 18.09.2020
comment
Ваш where в универсальном типе ограничивает TResult до Result<TResult, TData>. Тип object не соответствует этому ограничению   -  person Flydog57    schedule 18.09.2020
comment
@OlivierRogier - Нет, такая структура прекрасна. Попробуйте это: public class Foo : Result<Foo, object> { }. Вы можете без проблем создать экземпляр Foo.   -  person Enigmativity    schedule 18.09.2020
comment
Пожалуйста, не меняйте свой вопрос после того, как на него ответили. Неуважительно по отношению к сообществу Stack Overflow представлять движущуюся цель. На заданный вами вопрос был дан ответ. Добавление ограничений постфактум изменяет специфику вопроса таким образом, что часто обесцениваются усилия, уже затраченные на ответ на вопрос. Если вам нужен совет по более широкому сценарию, опубликуйте новый вопрос и объясните все об этом сценарии, в том числе, почему вам нужно использовать отражение и почему вам нужно получить доступ к свойству по определенному имени, а не выбирать его из списка свойств. .   -  person Peter Duniho    schedule 18.09.2020


Ответы (1)


К сожалению, оператор nameof не работает с непривязанные универсальные типы. Например. вы хотели бы иметь возможность писать nameof(Result<,>.Data) так же, как сегодня вы можете написать что-то вроде typeof(Result<,>). Таким образом, вам нужно будет указать параметры типа при попытке получить значение nameof(Result<TResult, TData>.Data).

Что вы пробовали, но указали object в качестве параметра типа для обоих параметров, хотя ваш общий тип ограничивает TResult производным от Result<TResult, TData>. Тип object не соответствует ограничению, так что это не может работать. Отсюда и ошибка компилятора.

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

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

Обратите внимание, что в контексте самого универсального типа вы можете ссылаться на свойство, не зная точных параметров типа, поскольку идентификатор свойства не нуждается в уточнении. Например. nameof(Data) будет работать для любого кода, который фактически находится в универсальном классе Result<TResult, TData>. Помогает ли это в вашем конкретном сценарии, неясно из предоставленной информации.

person Peter Duniho    schedule 18.09.2020
comment
например static string Name => nameof(Result<TResult, TData>.Data), теперь внешние классы могут ссылаться на DerivedResult<X,T>.Name. - person Jeremy Lakeman; 18.09.2020
comment
@JeremyLakeman: без параметров типа они не могут. В какой-то момент код, извлекающий имя, должен будет предоставить фактические типы, чтобы в конечном итоге был создан универсальный тип. И тогда они столкнутся с точно такой же проблемой в исходном вопросе. - person Peter Duniho; 18.09.2020