Getting started with C# LanguageVerbatim StringsOperatorsExtension MethodsCollection InitializersString InterpolationC# 6.0 FeaturesConstructors and FinalizersKeywordsGenericsReflectionInheritanceNull-Coalescing OperatorUsing StatementString Escape SequencesException HandlingNull-conditional OperatorsBuilt-in TypesLambda expressionsAsync-AwaitPropertiesThreadingUsing DirectiveMethodsYield KeywordEventsLINQ QueriesCommon String OperationsExpression TreesOverload ResolutionString.Formatnameof OperatorUnsafe Code in .NETInitializing PropertiesBindingList<T>ILGeneratorObject initializersXML Documentation CommentsPreprocessor directivesDynamic typeAnonymous typesStructsTuplesEnumAccess ModifiersTask Parallel LibraryAttributesGuidSingleton ImplementationDelegatesNullable typesGarbage Collector in .NetNetworkingArraysEquality OperatorLock StatementAction FiltersXmlDocument and the System.Xml namespaceDateTime MethodsBackgroundWorkerPolymorphismStatic ClassesIndexerIDisposable interfaceAliases of built-in typesImmutabilityXDocument and the System.Xml.Linq namespaceC# 7.0 FeaturesPerforming HTTP requestsGenerating Random Numbers in C#LoopingNamed ArgumentsDiagnosticsInterfacesIEnumerableNaming ConventionsAn overview of c# collectionsChecked and UncheckedRecursionFunctional ProgrammingLiteralsCastingNullReferenceExceptionFunc delegatesLINQ to XMLHash FunctionsHandling FormatException when converting string to other typesCryptography (System.Security.Cryptography)INotifyPropertyChanged interfaceValue type vs Reference typeC# 4.0 FeaturesIQueryable interfaceTask Parallel Library (TPL) Dataflow ConstructsStreamRuntime CompileConditional StatementsInteroperabilityOverflowEquals and GetHashCodeType ConversionParallel LINQ (PLINQ)String ManipulationString ConcatenatePartial class and methodsStopwatchesRegex ParsingC# ScriptC# 3.0 FeaturesAsync/await, Backgroundworker, Task and Thread ExamplesTimersFunction with multiple return valuesBinary SerializationMaking a variable thread safeIComparableCode ContractsIteratorsAssemblyInfo.cs ExamplesFile and Stream I/OCode Contracts and AssertionsCachingC# 5.0 FeaturesImplementing Flyweight Design PatternStringBuilderImplementing Decorator Design PatternAccessing DatabasesT4 Code GenerationMicrosoft.Exchange.WebServices.NET Compiler Platform (Roslyn)Data AnnotationUsing SQLite in C#System.Management.AutomationFileSystemWatcherSystem.DirectoryServices.Protocols.LdapConnectionNamed and Optional ArgumentsComments and regionsC# Authentication handlerPointers & Unsafe CodePointersHow to use C# Structs to create a Union type (Similar to C Unions)BigIntegerDependency InjectionReactive Extensions (Rx)Creational Design PatternsCreating a Console Application using a Plain-Text Editor and the C# Compiler (csc.exe)Reading and writing .zip filesGeneric Lambda Query BuilderImport Google ContactsLambda ExpressionsCLSCompliantAttributeObservableCollection<T>Synchronization Context in Async-AwaitICloneableRead & Understand StacktracesLinq to ObjectsASP.NET IdentityAccess network shared folder with username and passwordAsynchronous SocketStructural Design PatternsO(n) Algorithm for circular rotation of an arrayCreating Own MessageBox in Windows Form ApplicationIncluding Font ResourcesObject Oriented Programming In C#Using json.netGetting Started: Json with C#Windows Communication Foundation

Attributes

Other topics

Creating a custom attribute

//1) All attributes should be inherited from System.Attribute
//2) You can customize your attribute usage (e.g. place restrictions) by using System.AttributeUsage Attribute
//3) You can use this attribute only via reflection in the way it is supposed to be used
//4) MethodMetadataAttribute is just a name. You can use it without "Attribute" postfix - e.g. [MethodMetadata("This text could be retrieved via reflection")].
//5) You can overload an attribute constructors
[System.AttributeUsage(System.AttributeTargets.Method | System.AttributeTargets.Class)]
public class MethodMetadataAttribute : System.Attribute
{
    //this is custom field given just for an example
    //you can create attribute without any fields
    //even an empty attribute can be used - as marker
    public string Text { get; set; }

    //this constructor could be used as [MethodMetadata]
    public MethodMetadataAttribute ()
    {
    }

    //This constructor could be used as [MethodMetadata("String")]
    public MethodMetadataAttribute (string text)
    {
        Text = text;
    }
}

Using an attribute

[StackDemo(Text = "Hello, World!")]
public class MyClass
{
    [StackDemo("Hello, World!")]
    static void MyMethod()
    {
    }
}

Reading an attribute

Method GetCustomAttributes returns an array of custom attributes applied to the member. After retrieving this array you can search for one or more specific attributes.

var attribute = typeof(MyClass).GetCustomAttributes().OfType<MyCustomAttribute>().Single();

Or iterate through them

foreach(var attribute in typeof(MyClass).GetCustomAttributes()) {
    Console.WriteLine(attribute.GetType());
}

GetCustomAttribute extension method from System.Reflection.CustomAttributeExtensions retrieves a custom attribute of a specified type, it can be applied to any MemberInfo.

var attribute = (MyCustomAttribute) typeof(MyClass).GetCustomAttribute(typeof(MyCustomAttribute));

GetCustomAttribute also has generic signature to specify type of attribute to search for.

var attribute = typeof(MyClass).GetCustomAttribute<MyCustomAttribute>();

Boolean argument inherit can be passed to both of those methods. If this value set to true the ancestors of element would be also to inspected.

DebuggerDisplay Attribute

Adding the DebuggerDisplay Attribute will change the way the debugger displays the class when it is hovered over.

Expressions that are wrapped in {} will be evaluated by the debugger. This can be a simple property like in the following sample or more complex logic.

[DebuggerDisplay("{StringProperty} - {IntProperty}")]
public class AnObject
{
   public int ObjectId { get; set; }
   public string StringProperty { get; set; }
   public int IntProperty { get; set; }
}

DebuggerDisplay Example

Adding ,nq before the closing bracket removes the quotes when outputting a string.

[DebuggerDisplay("{StringProperty,nq} - {IntProperty}")]

Even though general expressions are allowed in the {} they are not recommended. The DebuggerDisplay attribute will be written into the assembly metadata as a string. Expressions in {} are not checked for validity. So a DebuggerDisplay attribute containing more complex logic than i.e. some simple arithmetic might work fine in C#, but the same expression evaluated in VB.NET will probably not be syntactically valid and produce an error while debugging.

A way to make DebuggerDisplay more language agnostic is to write the expression in a method or property and call it instead.

[DebuggerDisplay("{DebuggerDisplay(),nq}")]
public class AnObject
{
   public int ObjectId { get; set; }
   public string StringProperty { get; set; }
   public int IntProperty { get; set; }

   private string DebuggerDisplay()
    {
        return $"{StringProperty} - {IntProperty}"";
    }
}

One might want DebuggerDisplayto output all or just some of the properties and when debugging and inspecting also the type of the object.
The example below also surrounds the helper method with #if DEBUG as DebuggerDisplay is used in debugging environments.

[DebuggerDisplay("{DebuggerDisplay(),nq}")]
public class AnObject
{
   public int ObjectId { get; set; }
   public string StringProperty { get; set; }
   public int IntProperty { get; set; }

#if DEBUG
   private string DebuggerDisplay()
    {
        return
            $"ObjectId:{this.ObjectId}, StringProperty:{this.StringProperty}, Type:{this.GetType()}";
    }
    #endif
}

Caller info attributes

Caller info attributes can be used to pass down information about the invoker to the invoked method. The declaration looks like this:

using System.Runtime.CompilerServices;

public void LogException(Exception ex,
                         [CallerMemberName]string callerMemberName = "",
                         [CallerLineNumber]int callerLineNumber = 0,
                         [CallerFilePath]string callerFilePath = "")
{
    //perform logging
}

And the invocation looks like this:

public void Save(DBContext context)
{
    try
    {
        context.SaveChanges();
    }
    catch (Exception ex)
    {
        LogException(ex);
    }
}

Notice that only the first parameter is passed explicitly to the LogException method whereas the rest of them will be provided at compile time with the relevant values.

The callerMemberName parameter will receive the value "Save" - the name of the calling method.

The callerLineNumber parameter will receive the number of whichever line the LogException method call is written on.

And the 'callerFilePath' parameter will receive the full path of the file Save method is declared in.

Reading an attribute from interface

There is no simple way to obtain attributes from an interface, since classes does not inherit attributes from an interface. Whenever implementing an interface or overriding members in a derived class, you need to re-declare the attributes. So in the example below output would be True in all three cases.

using System;
using System.Linq;
using System.Reflection;

namespace InterfaceAttributesDemo {
    
    [AttributeUsage(AttributeTargets.Interface, Inherited = true)]
    class MyCustomAttribute : Attribute {
        public string Text { get; set; }
    }
    
    [MyCustomAttribute(Text = "Hello from interface attribute")]
    interface IMyClass {
        void MyMethod();
    }
    
    class MyClass : IMyClass {
        public void MyMethod() { }
    }
    
    public class Program {
        public static void Main(string[] args) {
            GetInterfaceAttributeDemo();
        }
        
        private static void GetInterfaceAttributeDemo() {
            var attribute1 = (MyCustomAttribute) typeof(MyClass).GetCustomAttribute(typeof(MyCustomAttribute), true);
            Console.WriteLine(attribute1 == null); // True
            
            var attribute2 = typeof(MyClass).GetCustomAttributes(true).OfType<MyCustomAttribute>().SingleOrDefault();
            Console.WriteLine(attribute2 == null); // True
            
            var attribute3 = typeof(MyClass).GetCustomAttribute<MyCustomAttribute>(true);
            Console.WriteLine(attribute3 == null); // True
        }
    }
}

One way to retrieve interface attributes is to search for them through all the interfaces implemented by a class.

var attribute = typeof(MyClass).GetInterfaces().SelectMany(x => x.GetCustomAttributes().OfType<MyCustomAttribute>()).SingleOrDefault();
Console.WriteLine(attribute == null); // False
Console.WriteLine(attribute.Text); // Hello from interface attribute

Obsolete Attribute

System.Obsolete is an attribute that is used to mark a type or a member that has a better version, and thus should not be used.

[Obsolete("This class is obsolete. Use SomeOtherClass instead.")]
class SomeClass
{
    //
}

In case the class above is used, the compiler will give the warning "This class is obsolete. Use SomeOtherClass instead."

Contributors

Topic Id: 1062

Example Ids: 3415,3416,3417,4689,6025,12245,17195

This site is not affiliated with any of the contributors.