Может ли функция вернуть экземпляр универсального класса неизвестного типа?

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

Тип может быть только одним из следующих значений перечисления:

public enum ImagePropertyType { SIZE, H_RES, V_RES, BIT_COUNT, IS_ALPHA }

Все значения имеют разные типы (Size, float, float, int, bool).

Упрощенная форма моего класса ImageProperty выглядит следующим образом:

public class ImageProperty
{
    private ImagePropertyType type;
    private object value;

    public ImageProperty(ImagePropertyType type, object value)
    {
        this.type = type;
        this.value = value;
    }

    public ImagePropertyType getType()
    {
        return this.type;
    }

    public void setType(ImagePropertyType type)
    {
        this.type = type
    }

    public object getValue()
    {
        return this.value;
    }        

    public void setValue(object value)
    {
        this.value = value;
    }
}

Обратите внимание на использование object для получения/установки значения (поскольку типы различаются).

Я хочу сделать свой класс универсальным, так как мне не нравится использовать объект, поэтому я вношу несколько изменений в класс и методы:

public class ImageProperty<T>
{
    ...
    private T value;
    ...
    public ImageProperty(ImagePropertyType type, T value)
    ...
    public T getValue()
    ...
    public void setValue(T value)
    ...
}    

У меня есть функция в другом классе, которая должна возвращать экземпляр ImageProperty на основе заданного типа.

public ???? getImageProperty(ImagePropertyType type, Bitmap bitMap)
{
    switch(type)
    {     
        case SIZE:
            return new ImageProperty<Size>(type, bitMap.Size);
        case H_RES:
            return new ImageProperty<float>(type, bitMap.HorizontalResolution);
        case V_RES:                            
            return new ImageProperty<float>(type, bitMap.VerticalResolution);
        ...
        ...
    }
}

Я не уверен, какой тип возврата использовать для этого метода (отсюда и ????).

Я не могу просто поставить:

public ImageProperty getImageProperty(ImagePropertyType type, Bitmap bitMap)

потому что класс ImageProperty должен быть параметризован.

Очевидно, что если бы тип значения всегда был, скажем, int, я бы установил тип возвращаемого значения:

public ImageProperty<int> getImageProperty(ImagePropertyType type, Bitmap bitMap)

Есть ли способ определить возвращаемый тип getImageProperty как "любое или неизвестное параметризованное значение"?

Что-то типа:

public ImageProperty<?> getImageProperty(ImagePropertyType type, Bitmap bitMap)

Не является ли параметрирование класса хорошей идеей, поскольку я не знаю, какой тип значения будет возвращен?

Должен ли я просто сделать класс ImageProperty необобщенным (как первый класс в моем сообщении) и вернуться к использованию объекта для типа возвращаемого значения, и если мне нужно знать тип значения, я могу просто получить его с помощью typeof?< /эм>

object value = getImageProperty(ImagePropertyType.SIZE, Bitmap bitMap).getValue();
Type t = typeof(value);

Спасибо.

----ОБНОВИТЬ---------------------------------

Основываясь на предложении Кнагиса и дальнейшем чтении, я решил сохранить исходный класс, а затем создать общий класс, который расширяет ImageProperty:

public class ImageProperty<T> : ImageProperty
{
    private T propertyValue;

    public ImageProperty()
        : base()
    {
    }

    public ImageProperty(ImagePropertyType propertyType, T propertyValue)
        : base(propertyType, propertyValue)
    {
        this.propertyValue = propertyValue;
    }

    public T getPropertyValue()
    {
        return propertyValue;
    }

    public void setPropertyValue(T propertyValue)
    {
        this.propertyValue = propertyValue;
    }
}    

Однако есть одна вещь. Я получаю предупреждение компилятора, в котором говорится:

ImageProperty<T>.getPropertyValue() hides inherited member ImageProperty.getPropertyValue(). Use the new keyword if hiding was intended.

Я добавил ключевое слово новое:

публичный новый T getPropertyValue()

Странно, я никогда не знал о ключевом слове new, используемом в объявлении метода, и о том, как оно используется. Кто-нибудь хочет объяснить?



person Jan Tacci    schedule 10.10.2013    source источник
comment
ключевое слово new просто используется, чтобы разработчик мог сообщить компилятору, что вы на самом деле хотите, чтобы метод имел то же имя, что и базовый метод (который становится недоступным для вашего нового метода). Метод работает одинаково даже без ключевого слова.   -  person Knaģis    schedule 10.10.2013


Ответы (1)


В вашем случае единственное, что вы можете сделать, это попросить метод вернуть определенный тип:

public ImageProperty<T> getImageProperty<T>(ImagePropertyType type, Bitmap bitMap)

// call the method
ImageProperty<int> result = obj.getImageProperty<int>(ImagePropertyType.SIZE, bitmap).

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

// class
public class ImageProperty<T> : ImageProperty {}

// and methods that can be used (you can only use one of these unless you rename one)
public ImageProperty<T> getImageProperty<T>(ImagePropertyType type, Bitmap bitMap)
public ImageProperty getImageProperty(ImagePropertyType type, Bitmap bitMap)
person Knaģis    schedule 10.10.2013
comment
@ p.s.w.g Я собирался сказать то же самое. ImagePropertyType — это перечисление. - person Jan Tacci; 10.10.2013
comment
Я делаю то, что Кнагис сказал в своем последнем абзаце. Я создаю необщий базовый класс, а затем наследую от него универсальный класс. - person Jan Tacci; 10.10.2013
comment
@ p.s.w.g - да, вы правы, переписали ответ, чтобы лучше относиться к типам, используемым в вопросе - person Knaģis; 10.10.2013
comment
Knaģis, пожалуйста, посмотрите мой обновленный пост в разделе ОБНОВЛЕНИЕ внизу, чтобы увидеть, что я решил сделать. Как вы предложили, я сделал ImageProperty базовым классом, а затем создал еще один класс, ImageProperty‹T›, который его расширяет. - person Jan Tacci; 10.10.2013
comment
@Knaģis Это для исправления, но вам, вероятно, следует продемонстрировать, как реализовать ImageProperty<T> : ImageProperty (скрывая базовый метод). - person p.s.w.g; 10.10.2013
comment
Вы имеете в виду мой комментарий относительно предупреждения компилятора? Тот, в котором говорится, что getPropertyValue скрывает метод в базовом классе? Если это так, я добавил ключевое слово new в соответствии с предупреждением компилятора, и оно исчезло. - person Jan Tacci; 10.10.2013