Как использовать статический служебный метод для установщиков свойств в служебном классе

Я пытаюсь добиться двустороннего связывания между 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. Это правильное предположение?

Мой второй ВОПРОС показывает, какой я новичок в 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
ни параметр с именем value, где вызывается метод 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: Все не пустые методы должны иметь явные операторы возврата.

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 означает, что параметр передается как ссылка, и что изменения, внесенные в параметр в теле функции, будут распространяться на значение параметра в контексте вызывающей функции.

  • Похоже, тип возвращаемого значения должен быть изменен с 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 это общий тип и действует как заполнитель для того, что тип на самом деле. Он выясняет, какой тип автоматически, основываясь на типе аргумента, который вы ему передаете. (Если вы передаете это stringT действует точно так же, как если бы вы использовали string вместо T.)

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

Другие вопросы по тегам