Инициализировать делегата с анонимной функцией - PullRequest
0 голосов
/ 20 мая 2018

У меня есть какое-то оборудование, которое существует в различных моделях, и я пишу программное обеспечение, которое будет управлять им с помощью различных графических интерфейсов.У меня есть класс, представляющий аппаратное обеспечение, у которого есть такие свойства, как напряжение, скорость, размер и т. Д. Я хотел бы упростить доступ к этим свойствам, создав следующий класс:

    public class CProperty
    {
        public CProperty(string name, Func<object> get, Action<object> set)
        {
            this.name = name;
            this.get = get;
            set = set;
        }
        private string name;
        public Func<object> get;
        public Action<object> set;
        private object value;
    }

Тогда я мог быинициализируйте их массив следующим образом:

    public CProperty[] Properties = new CProperty[]
    {
        new CProperty(
            "name1",
            new Func<float>(() => value),
            new Action<float>((v) => value = v)
            ),
    };

Затем массив можно превратить в класс коллекции с индексатором, который использует имя свойства в качестве индекса.Но когда я пытаюсь это сделать, при инициализации массива поле «значение» не входит в область действия инициализаторов функций set и get, и я не понимаю, почему.

Ответы [ 2 ]

0 голосов
/ 20 мая 2018

Я не совсем понимаю, чего вы собираетесь достичь здесь.

Глядя на код, я могу сказать, что вы пытаетесь переопределить концепцию свойства - у вас есть поддержкаполе value и метод получения с сеттером, выраженным делегатами.

Глядя на описание,

класс коллекции с индексатором, который использует имя свойства в качестве индекса

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

По крайней мере, я могу ответить на эту часть

Но когда я пытаюсь это сделать, при инициализации массива поле «значение» не находится в области видимости в инициализаторахдля функций set и get, и я не понимаю, почему.В этом случае имеет смысл различать лексическую и динамическую область действия .Лексическая или статическая область видимости определяется посредством расположения в исходном коде вашей программы, в то время как динамическая область видимости строится на фактическом пути выполнения.C # имеет лексическую область видимости, и по этой причине ваши делегаты, объявленные извне класса CProperty, не могут получить доступ к полю value, несмотря на то, что они фактически вызываются внутри.

value - это поле, которое находится в области действия класса CProperty, поэтому оно видно только членам этого класса.Внешний мир может получить доступ к этому полю через экземпляр CProperty (но только если вы сделаете поле public).

var prop = new CProperty(/*ctor parameters*/)
var value = prop.value;
0 голосов
/ 20 мая 2018

Нельзя преобразовать Func<float> в Func<object>, а также Action<float> в Action<object>.Это связано с тем, что ковариация и контравариантность плохо сочетаются с типами значений (в итоге ковариация и контравариантность - это ловкость рук, а не реальные преобразования между типами, и поэтому требуют, чтобы оба типа имели одинаковую структуру памяти ...ссылка, так что легко сделать ковариацию / контравариантность между двумя ссылками, но float - это тип значения, который сильно отличается от object, который является ссылочным типом)

И вв обоих случаях вы должны добавить параметр типа CProperty к Func/Action, например Func<CProperty, float>(cp => cp.value), но value должен быть public ... Это потому, что анонимные методы являются "статическими", они не имеют свободныхдоступ к справочнику this, поэтому вы должны передать его в качестве параметра ...

public class CProperty
{
    public CProperty(string name, Func<CProperty, object> get, Action<CProperty, object> set)
    {
        this.name = name;
        this.get = get;
        this.set = set;
    }
    private string name;
    public Func<CProperty, object> get;
    public Action<CProperty, object> set;
    public object value;
}

var properties = new CProperty[]
{
    new CProperty(
        "name1",
        new Func<CProperty, object>(cp => cp.value),
        new Action<CProperty, object>((cp, v) => cp.value = v)
    ),
};

, или вы можете даже захватить this:

public class CProperty
{
    public CProperty(string name, Func<CProperty, Func<object>> get, Func<CProperty, Action<object>> set)
    {
        this.name = name;
        this.get = get(this);
        this.set = set(this);
    }
    private string name;
    public Func<object> get;
    public Action<object> set;
    public object value;
}   

var properties = new CProperty[]
{
    new CProperty(
        "name1",
        cp => new Func<object>(() => cp.value),
        cp => new Action<object>((v) => cp.value = v)
    ),
};

ВВ конце концов, я думаю, что вы довольно далеки от того, что хотите ... вам придется вернуться к доске с классом CProperty.

...