C #: свойства с различными типами возврата в производных классах - PullRequest
7 голосов
/ 13 ноября 2011

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

С базовым классом, который выглядит как

abstract public class Property
{
    private String name;

    public Property(String propertyName)
    { 
        name = propertyName; 
    }

    public String Name
    {
        get { return name; }
    }

    abstract public override String ToString();
}

И производные классы, которые выглядят как

public class StringProperty : Property
{
    private String value; // different properties for different types

    public StringProperty(String propertyName, String value) : base(propertyName)
    {
        this.value = value;
    }

    public String Value // different signature for different properties
    {
        get { return value; }
    }

    public override String ToString()
    {
        return base.Name + ": " + value;
    }
}

Во время выполнения функция получает коллекцию объектов «Свойство». Что мне нужно сделать, чтобы получить «ценность» каждого? Нужно ли иметь большой оператор if для запроса типа каждого объекта «Свойство»? Если нет, есть ли более элегантное решение?

Я попытался определить абстрактное свойство «Значение», которое должно быть переопределено, но, поскольку возвращаемые типы отличаются, оно не сработало. Я также попытался поиграть с затенением свойства «Value», но не смог заставить его работать. Идея использования COM-подобного варианта тоже не очень уместна.

Заранее большое спасибо.

EDIT:

Я должен был добавить подробности о том, что я пытаюсь сделать. Свойства отображаются в приложении Winforms. Различные «TextBox» представляют разные свойства и фильтруются для правильного ввода (в зависимости от типа). Обновленные значения считываются и сохраняются. Контейнерный объект будет сериализован в JSON и десериализован на клиенте для Android и iPhone, и в конечном итоге эти значения будут переданы в слой с собственным кодом C ++, выполняющим OpenGL. Я не знаю заранее всех необходимых свойств, поэтому, как посредник, я хотел сделать свой код максимально надежным, в то же время имея возможность использовать движок OpenGL.

Ответы [ 4 ]

13 голосов
/ 13 ноября 2011

Вы можете использовать универсальный класс:

public class AnyProperty<T> : Property
{
    private T value;
    // ... etc

Я бы действительно рекомендовал сделать базовый класс интерфейсом:

public interface IProperty
{
    public String Name { get; }
}

public class Property<T> : IProperty
{
    public Property(String name, T value)
    {
        Name = name;
        Value = value;
    }

    public String Name { get; private set; }
    public T Value { get; private set; }

    public override String ToString()
    {
        return string.Format("{0}: {1}", Name, Value)
    }
}

Вот пример использования:

var intProp = new Property<int>       ("age", 32);    
var strProp = new Property<string>    ("name", "Earl");    
var enumProp = new Property<ColorEnum> ("eye color", ColorEnum.Magenta);    

Чтобы сделать конструкцию еще проще, вы можете использовать фабричный метод:

public static Property<T> MakeProperty(string name, T value)
{
    return new Property<T>(name,value);
}

var intProp = MakeProperty("age", 32);    
var strProp = MakeProperty("name", "Earl");    
var enumProp = MakeProperty("eye color", ColorEnum.Magenta);    

Не обязательно рекомендуется и немного OT:

Вы можете сделать его еще более интересным с помощью метода расширения:

public static Property<T> AsProp<T>(this T value, string name)
{
    return new Property<T>(name,value);
}

var intProp = 32.AsProp("age");
var strProp = "Earl".AsProp("name");
var enumProp = ColorEnum.Magenta.AsProp("eye color");

3 голосов
/ 13 ноября 2011

Вы должны просто использовать тип object.Что вы пытаетесь достичь?Проблема здесь не в структуре ваших классов, а в функции, которая получает коллекцию Property объектов.Невозможно даже преобразовать что-либо к неизвестному типу, так как вы не знаете, в каком типе переменной оно должно храниться.

Таким образом, ваше свойство Property.Value должно иметь тип object,В вашем методе, который использует Property объекты, вам нужно что-то с ними делать, и то, что вы делаете, решит, как это должно быть структурировано.Вы печатаете ценности?Имейте класс *Value, унаследованный от абстрактного класса PropertyValue, и переопределите ToString(), чтобы вернуть соответствующее строковое представление.

2 голосов
/ 13 ноября 2011

Это потребует некоторого переосмысления, но вы рассматривали возможность использования динамического типа (представлен в .net4)

На самом деле не решает вашу проблему, но обходит ее стороной. Ваши свойства могут просто быть

Dictionary<String, dynamic>

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

так что вы хотите int SomeValue = MyProperties [SomePropertyName] + 10;

Так что если MyProperties [SomePropertyName] = 10; // все хорошо

если его 76,52 или Фред, сложение выдаст исключение в тот момент, когда оно выполнится.

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

2 голосов
/ 13 ноября 2011

Я внес несколько изменений в ваш пример кода и получил этот результат ...

   abstract public class Property
    {
        private readonly String _name;
        public Property(String propertyName)
        {
            _name = propertyName;
        }
        public String Name
        {
            get { return _name; }
        }
        abstract public override String ToString();
    }
    public class StringProperty : Property
    {
        private readonly dynamic _value; // different properties for different types 
        public StringProperty(String propertyName, dynamic value)
            : base(propertyName)
        {
            this._value = value;
        }
        public dynamic Value // different signature for different properties 
        {
            get { return _value; }
        }
        public override String ToString()
        {
            return base.Name + ": " + _value;
        }
    }
    static void Main(string[] args)
    {
        StringProperty sp = new StringProperty("A double", 3.444);
        StringProperty sp2 = new StringProperty("My int", 4343);
        StringProperty sp3 = new StringProperty("My directory", new  DirectoryInfo("Some directory"));
        StringProperty sp4 = new StringProperty("My null", null);
        Console.WriteLine(sp);
        Console.WriteLine(sp2);
        Console.WriteLine(sp3);
        Console.WriteLine(sp4);
    }
}

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

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