Подтвердить что ты не робот

С#, доступ к статическому свойству типа T в общем классе

Я пытаюсь выполнить следующий сценарий, что общий TestClassWrapper сможет получить доступ к статическим свойствам классов, из которых он сделан (все они будут получены из TestClass). Что-то вроде:

public class TestClass
{
    public static int x = 5;
}

public class TestClassWrapper<T> where T : TestClass
{
    public int test()
    {
        return T.x;
    }
}

Дает ошибку: 'T' is a 'type parameter', which is not valid in the given context.

Любые предложения?

4b9b3361

Ответ 1

Вы не можете, в основном, по крайней мере, не без размышлений.

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

var wrapper = new TestClassWrapper<TestClass>(() => TestClass.x);

Вы можете сделать это с отражением, если необходимо:

public class TestClassWrapper<T> where T : TestClass
{
    private static readonly FieldInfo field = typeof(T).GetField("x");

    public int test()
    {
        return (int) field.GetValue(null);
    }
}

(При необходимости добавьте соответствующие флаги привязки).

Это не очень хорошо, но по крайней мере вам нужно всего лишь разглядеть поле...

Ответ 2

Конечно, вы можете просто написать это:

public int test() 
{ 
    return TestClass.x; 
} 

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

Ответ 3

Почему бы просто не вернуть TestClass.x?

Ответ 4

В этой ситуации вы предполагаете, что T является подклассом TestClass. Подклассы TestClass не будут иметь статический int x.

Ответ 5

Generics не поддерживает ничего, связанное со статическими членами, так что это не сработает. Мой совет: не делайте его статичным. Предполагая, что поле действительно относится к конкретному T, вы также можете использовать отражение:

return (int) typeof(T).GetField("x").GetValue(null);

но я не рекомендую его.

Ответ 6

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

public class UrlRecordService
{
    public virtual void SaveSlug<T>(T entity) where T : ISlugSupport
    {
        if (entity == null)
            throw new ArgumentNullException("entity");

        int entityId = entity.Id;
        string entityName = typeof(T).Name;
    }
}


public interface ISlugSupport
{
    int Id { get; set; }
}

Ответ 7

Другим решением является просто не сделать его статическим и работать с ограничением new() на T, чтобы создать экземпляр объекта. Затем вы можете работать с интерфейсом, и оболочка может получить свойство из любого класса, который реализует этот интерфейс:

public interface XExposer
{
    Int32 X { get; }
}

public class TestClass : XExposer
{
    public Int32 X { get { return 5;} }
}

public class XExposerWrapper<T> where T : XExposer, new()
{
    public Int32 X
    {
        get { return new T().X; }
    }
}

Фактически вы можете изменить это на public static Int32 X на TestClassWrapper и просто получить его как Int32 fetchedX = XExposerWrapper<TestClass>.X;

Хотя, поскольку любые вызовы кода должны будут давать параметр T тем же самым ограничениям, класс-оболочка на данный момент довольно ненужен, так как сам этот код вызова также может просто выполнить new T().X и не беспокоить оболочку.

Тем не менее, есть некоторые интересные модели наследования, где такая структура полезна. Например, abstract class SuperClass<T> where T : SuperClass<T>, new() может создавать и возвращать тип T в своих статических функциях, эффективно позволяя создавать наследуемые статические функции, которые адаптируются к дочерним классам (которые затем должны определяться как class ChildClass : SuperClass<ChildClass>). Определяя protected abstract функции/свойства суперкласса, вы можете создавать функции, которые применяют одну и ту же логику к любому наследуемому объекту, но настраиваются под этот подкласс в соответствии с его реализацией этих тезисов. Я использую это для классов базы данных, где запрос имени таблицы и выборки реализуется дочерним классом. Поскольку свойства защищены, они также не подвергаются воздействию.