Как использовать статический служебный метод для установщиков свойств в служебном классе - PullRequest
1 голос
/ 21 июля 2011

Я пытаюсь добиться двустороннего связывания между DataGridView и BindingList, который предоставляет данные для DGV. Некоторые столбцы еще не отражают изменения в базовом списке, и я думаю, что это потому, что я не предоставил установщик (и) свойств для уведомления об изменениях свойств. Вместо того, чтобы кодировать установщик для свойства Rows так же, как я делал для свойства Process, я пытаюсь стать более «элегантным» и понимаю, что застрял ....

Я наткнулся на очень интересную рецензию для более элегантного подхода и пытаюсь реализовать ее концепции (см. Пожалуйста): http://www.gavaghan.org/blog/2007/07/17/use-inotifypropertychanged-with-bindinglist/

Вот код из статьи Майка, которую я хочу использовать (установлен как Utilities.cs в моем проекте CBMI.Common):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
namespace CBMI.Common
{
public static class Utilities
{
    public static bool Set<T>(object owner, string propName,
        ref T oldValue, T newValue, PropertyChangedEventHandler eventHandler)
    {
        // make sure the property name really exists
        if (owner.GetType().GetProperty(propName) == null)
        {
            throw new ArgumentException("No property named '" + propName + "' on " + owner.GetType().FullName);
        }
        if (!Equals(oldValue, newValue))  // we only raise an event if the value has changed
        {
            oldValue = newValue;
            if (eventHandler != null)
            {
                eventHandler(owner, new PropertyChangedEventArgs(propName));
            }
        }
    return true;    // Please NOTE: I had to add this statement to avoid compile error:
        // "not all code paths return a value".
    }
}
}

Итак, мой ПЕРВЫЙ ВОПРОС об этом: у автора в его статье не было оператора return , и я добавил его, что устранило ошибку компилятора. Я предполагаю, что eventHandler выполняется и возвращается, и это было упущение автора, и это должно вернуть true, так как метод хочет тип возврата bool. Это правильное предположение?

Мой 2-й ВОПРОС показывает, какой я новичок в C #, когда пытаюсь использовать этот вспомогательный метод выше. Я закодировал этот класс в отдельный файл с именем InputFileInfo.cs в том же проекте (и пространстве имен), что и выше:

    using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
namespace CBMI.Common
{
    public class InputFileInfo : INotifyPropertyChanged
    {
    private bool processThisFile;
    public bool Process
    {
        get { return processThisFile; }
        set
        {
        processThisFile = value;
        this.NotifyPropertyChanged("Process");
        }
    }

    public string FileName { get; set; }

    private long rowsReturned;
    public long Rows
    {
        get { return rowsReturned; }
        set
        {
        Utilities.Set(this, "Rows", ref rowsReturned, value, PropertyChanged);
        }

    }
    public string Message { get; set; } 

    // constructor
    public InputFileInfo(string fName)
    {
        Process = true;
        FileName = fName;
        Rows = 0;
        Message = String.Empty;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(string name)
    {
        if (PropertyChanged != null)
        PropertyChanged(this, new PropertyChangedEventArgs(name));
    }
    }
}

Сеттер для второго свойства в этом классе - это место, где я пытаюсь использовать статический метод Майка:

Utilities.Set(this, "Rows", ref rowsReturned, value, PropertyChanged);

Если я удаляю Utilities.Set и просто кодирую его следующим образом:

Set(this, "Rows", ref rowsReturned, value, PropertyChanged);

.. тогда я получаю компилятор с жалобой, что "имя 'Set' не существует в текущем контексте" .

Я попытался добавить с помощью утилит; директива но это не решило проблему.

Наконец, я не понимаю параметры: ref T oldValue, T newValue
ни параметр с именем значение , где вызывается метод Set.

Может кто-нибудь помочь мне разобраться с этими многочисленными заблуждениями относительно этого кода, чтобы я мог использовать эти более продвинутые идеи?

---- РЕДАКТИРОВАТЬ ОБНОВЛЕНИЕ ---- Два хороших ответа помогли мне получить эту работу. "Второй вопрос" в оригинальном посте выше остается немного неуловимым. Добавлены комментарии для каждого запроса «наилучшей практики» о том, как упаковать это, чтобы я мог использовать простой синтаксис вызова, как в оригинальной статье Майка. То есть я пытаюсь вызвать "вспомогательные" статические методы только по имени метода. Я хочу понять, как вызвать как:

set
{
    Set(this, "Rows", ref rowsReturned, value, PropertyChanged);
}

вместо того, чтобы кодировать как:

set
{
    Utilities.Set(this, "Rows", ref rowsReturned, value, PropertyChanged);
}

Я получил это с помощью кодирования Utilities.Set, но я предполагаю, что вопрос немного превращается в - "Где я могу поместить статические методы и как их вызывать, чтобы мне не нужно было" квалифицировать " их с именем класса? " Я хотел бы понять, как упаковать обычно полезные методы типа" утилиты ", которые не требуют экземпляра объекта. В этом случае статический метод называется Set, но я хотел бы иметь возможность добавлять другие статические методы, такие как:

public static int HelpfulMethodXXXX(string s, int num)

У меня есть отдельно скомпилированная DLL (проект Vstudio), содержащая только файлы классов. В конечном счете, я хотел бы думать, что я мог бы использовать этот класс в других приложениях.

Где лучшее место для объявления таких статических методов, чтобы их можно было вызывать как:

int i = HelpfulMethodXXXX("Sample", testNumber);

вместо:

int i = ContainingClassName.HelpfulMethodXXXX("Sample", testNumber);

Ответы [ 2 ]

1 голос
/ 21 июля 2011
  • Похоже, что тип возвращаемого значения должен быть изменен с bool на void, поскольку, похоже, он никогда не возвращает разные значения.

  • Да, Utilities.Set - правильный синтаксис. Например, в Java нет аналога статического импорта, поэтому вы должны квалифицировать его как класс. Вы можете использовать методы расширения, если вы выбрали, и иметь возможность вызывать метод наподобие this.Set(...). Для этого просто добавьте ключевое слово this перед первым параметром в вашем методе Set:

public static bool Set<T>(this object owner, string propName,
    ref T oldValue, T newValue, PropertyChangedEventHandler eventHandler)
  • ref T oldValue означает, что вы можете передать ей переменную типа T, и она запишет в нее старое значение (другими словами, передачу по ссылке для типов значений). Таким образом, вы можете узнать, что было oldValue. (хотя мне кажется, что параметр out имел бы больше смысла.)

  • T newValue - это новое значение, которое вы пытаетесь установить. Если вы спрашиваете, что такое T, это универсальный тип, который действует как заполнитель для типа , действительно . Он выясняет, какой тип автоматически, основываясь на типе аргумента, который вы ему передаете. (Если вы передадите ему string, T будет действовать точно так же, как если бы вы использовали string вместо T.)

  • value - это специальное ключевое слово в C #, которое имеет специальное значение только в аксессоре set определенного вами свойства. Это значение, которое вы пытаетесь присвоить свойству.

1 голос
/ 21 июля 2011

1: Все не пустые методы должны иметь явные операторы возврата.

2: CMBI.Common - это пространство имен. Утилиты это название вашего класса. Set () является функцией вашего класса.

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

Использование операторов может включать только пространства имен (CMBI.Common) или определенные классы внутри пространств имен, если вы не хотите, чтобы каждый класс в пространстве имен (CMBI.Common.Utilities). Однако они не могут превратить функцию класса в глобальную функцию.

3: T относится к имени общего типа, с которым работает эта функция. http://msdn.microsoft.com/en-us/library/ms379564(v=vs.80).aspx

Обобщения позволяют одному и тому же коду управлять, скажем, набором целых чисел и набором строк, обеспечивая при этом безопасность типов во время компиляции (компилятор выдаст ошибку, если вы попытаетесь вставить целое число в набор строки.)

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

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