Когда вы пишете свой код, вы отвечаете «что?» вопрос:
- что делать? (методы)
- что хранить? (поля и свойства)
- что есть что? (иерархия классов)
и т.д.. Атрибуты добавляют еще одно измерение к этому вопросу. Они отвечают "как?" вопрос. И ответ на "как?" вопрос может быть важным для IDE,
[Browsable(false)]
public string NotImportantField { get; set; } // property which will not be displayed in VS
для компилятора
[ThreadStatic]
private static RequestContext context; // field which will be different for every thread
или для другого кода, который анализирует ваш с помощью отражения.
[XmlIgnore]
public string NotSerializableField { get; set; } // property which will not be xml-serialized
вы можете захотеть определить пользовательские атрибуты, если ваши сборки, классы, поля, методы и т. Д. Будут проанализированы или вызваны с помощью отражения (что часто имеет место, например, с инверсией контейнеров управления и аспектно-ориентированным программированием). Такой атрибут может (и часто является единственным способом) указывать вызывающему или анализатору вести себя по-разному в зависимости от наличия такого атрибута или его свойств.
По поводу вашего первого вопроса, ну как мы узнаем, какой метод вызывать для определенного результата? Одним из преимуществ разработки .NET является то, что все задокументировано довольно тщательно. :)