Suche…


Syntax

  • public void SomeMethod <T> () { }
  • public void SomeMethod<T, V>() { }
  • public T SomeMethod<T>(IEnumerable<T> sequence) { ... }
  • public void SomeMethod<T>() where T : new() { }
  • public void SomeMethod<T, V>() where T : new() where V : struct { }
  • public void SomeMethod<T>() where T: IDisposable { }
  • public void SomeMethod<T>() where T: Foo { }
  • public class MyClass<T> { public T Data {get; set; } }

Parameter

Parameter Beschreibung
FERNSEHER Geben Sie Platzhalter für generische Deklarationen ein

Bemerkungen

Generics in C # werden bis zur Laufzeit vollständig unterstützt: Generische Typen, die mit C # erstellt wurden, behalten ihre generische Semantik selbst nach der Kompilierung in CIL .

Dies bedeutet effektiv, dass es in C # möglich ist, generische Typen zu reflektieren und sie so zu sehen, wie sie deklariert wurden, oder zu überprüfen, ob ein Objekt beispielsweise eine Instanz eines generischen Typs ist. Dies steht im Gegensatz zur Typlöschung , bei der generische Typinformationen während des Kompilierens entfernt werden. Dies steht auch im Gegensatz zum Vorlagenansatz für Generika, bei dem mehrere konkrete generische Typen zur Laufzeit zu mehreren nicht generischen Typen werden und alle Metadaten, die zur weiteren Instanziierung der ursprünglichen generischen Typdefinitionen erforderlich sind, verloren gehen.

Seien Sie jedoch vorsichtig, wenn Sie über generische Typen nachdenken: Die Namen generischer Typen werden beim Kompilieren geändert. Dabei werden die spitzen Klammern und die Namen der Typparameter durch ein Backtick gefolgt von der Anzahl der generischen Typparameter ersetzt. Daher wird ein Dictionary<TKey, Tvalue> in Dictionary`2 übersetzt.

Typparameter (Klassen)

Erklärung:

class MyGenericClass<T1, T2, T3, ...>
{
    // Do something with the type parameters.
}

Initialisierung:

var x = new MyGenericClass<int, char, bool>();

Verwendung (als Typ eines Parameters):

void AnotherMethod(MyGenericClass<float, byte, char> arg) { ... }

Typparameter (Methoden)

Erklärung:

void MyGenericMethod<T1, T2, T3>(T1 a, T2 b, T3 c)
{
    // Do something with the type parameters.
}

Aufruf:

Es gibt keine Notwendigkeit, Typ-Argumente für eine genric-Methode bereitzustellen, da der Compiler implizit auf den Typ schließen kann.

int x =10;
int y =20;
string z = "test";
MyGenericMethod(x,y,z);

Bei Unklarheiten müssen jedoch generische Methoden mit type arguemnts as aufgerufen werden

MyGenericMethod<int, int, string>(x,y,z);

Typparameter (Schnittstellen)

Erklärung:

interface IMyGenericInterface<T1, T2, T3, ...> { ... }

Verwendung (in Vererbung):

class ClassA<T1, T2, T3> : IMyGenericInterface<T1, T2, T3> { ... }

class ClassB<T1, T2> : IMyGenericInterface<T1, T2, int> { ... }

class ClassC<T1> : IMyGenericInterface<T1, char, int> { ... }

class ClassD : IMyGenericInterface<bool, char, int> { ... }

Verwendung (als Typ eines Parameters):

void SomeMethod(IMyGenericInterface<int, char, bool> arg) { ... }

Implizite Typinferenz (Methoden)

Bei der Übergabe formeller Argumente an eine generische Methode können relevante generische Typargumente normalerweise implizit abgeleitet werden. Wenn alle generischen Typen abgeleitet werden können, ist die Angabe in der Syntax optional.

Betrachten Sie die folgende generische Methode. Es hat einen formalen Parameter und einen generischen Typparameter. Es gibt eine sehr offensichtliche Beziehung zwischen ihnen - der Typ, der als Argument an den generischen Typparameter übergeben wird, muss dem Typ der Kompilierungszeit des an den Formalparameter übergebenen Arguments entsprechen.

void M<T>(T obj)
{
}

Diese beiden Aufrufe sind gleichwertig:

M<object>(new object());
M(new object());

Diese beiden Aufrufe sind auch gleichwertig:

M<string>("");
M("");

Und so sind diese drei Aufrufe:

M<object>("");
M((object) "");
M("" as object);

Beachten Sie, dass alle Argumente angegeben werden müssen, wenn mindestens ein Typargument nicht abgeleitet werden kann.

Betrachten Sie die folgende generische Methode. Das erste generische Typargument ist mit dem Typ des formalen Arguments identisch. Es gibt jedoch keine solche Beziehung für das zweite generische Typargument. Daher kann der Compiler bei einem Aufruf dieser Methode nicht auf das zweite generische Typargument schließen.

void X<T1, T2>(T1 obj)
{
}

Das funktioniert nicht mehr:

X("");

Dies funktioniert auch nicht, weil der Compiler nicht sicher ist, ob wir den ersten oder den zweiten generischen Parameter angeben (beide wären als object gültig):

X<object>("");

Wir müssen beide wie folgt eingeben:

X<string, object>("");

Typeinschränkungen (Klassen und Schnittstellen)

Typeinschränkungen können einen Typparameter zwingen, eine bestimmte Schnittstelle oder Klasse zu implementieren.

interface IType;
interface IAnotherType;

// T must be a subtype of IType
interface IGeneric<T>
    where T : IType
{
}

// T must be a subtype of IType
class Generic<T>
    where T : IType
{
}

class NonGeneric
{
    // T must be a subtype of IType
    public void DoSomething<T>(T arg)
        where T : IType
    {
    }
}

// Valid definitions and expressions:
class Type : IType { }
class Sub : IGeneric<Type> { }
class Sub : Generic<Type> { }
new NonGeneric().DoSomething(new Type());

// Invalid definitions and expressions:
class AnotherType : IAnotherType { }
class Sub : IGeneric<AnotherType> { }
class Sub : Generic<AnotherType> { }
new NonGeneric().DoSomething(new AnotherType());

Syntax für mehrere Einschränkungen:

class Generic<T, T1>
    where T : IType 
    where T1 : Base, new()
{
}

Typeinschränkungen funktionieren auf dieselbe Weise wie Vererbung, da es möglich ist, mehrere Schnittstellen als Einschränkungen für den generischen Typ anzugeben, jedoch nur eine Klasse:

class A { /* ... */ }
class B { /* ... */ }

interface I1 { }
interface I2 { }

class Generic<T>
    where T : A, I1, I2
{
}

class Generic2<T>
    where T : A, B //Compilation error
{
}

Eine andere Regel ist, dass die Klasse als erste Einschränkung und dann die Schnittstellen hinzugefügt werden muss:

class Generic<T>
    where T : A, I1
{
}

class Generic2<T>
    where T : I1, A //Compilation error
{
}

Alle deklarierten Bedingungen müssen gleichzeitig erfüllt sein, damit eine bestimmte generische Instantiierung funktioniert. Es gibt keine Möglichkeit, zwei oder mehr alternative Sätze von Abhängigkeiten anzugeben.

Typeinschränkungen (Klasse und Struktur)

Es ist möglich, festzulegen , ob das Argument Typ unter Verwendung der jeweiligen Einschränkungen ein Referenztyp oder ein Werttyp sein sollte class oder struct . Wenn diese Einschränkungen verwendet werden, müssen sie definiert werden, bevor alle anderen Einschränkungen (z. B. ein übergeordneter Typ oder new() ) aufgelistet werden können.

// TRef must be a reference type, the use of Int32, Single, etc. is invalid.
// Interfaces are valid, as they are reference types
class AcceptsRefType<TRef>
    where TRef : class
{
    // TStruct must be a value type.
    public void AcceptStruct<TStruct>()
        where TStruct : struct
    {
    }

    // If multiple constraints are used along with class/struct
    // then the class or struct constraint MUST be specified first
    public void Foo<TComparableClass>()
        where TComparableClass : class, IComparable
    {
    }
}

Typeinschränkungen (neues Schlüsselwort)

Mithilfe der new() Einschränkung können Sie Typparameter erzwingen, um einen leeren (Standard-) Konstruktor zu definieren.

class Foo
{
    public Foo () { }
}

class Bar
{
    public Bar (string s) { ... }
}

class Factory<T>
    where T : new()
{
    public T Create()
    {
        return new T();
    }
}

Foo f = new Factory<Foo>().Create(); // Valid.
Bar b = new Factory<Bar>().Create(); // Invalid, Bar does not define a default/empty constructor.

Der zweite Aufruf von Create() führt zu einer Kompilierzeit mit der folgenden Nachricht:

'Bar' muss ein nicht abstrakter Typ mit einem öffentlichen parameterlosen Konstruktor sein, um ihn als Parameter 'T' im generischen Typ oder der generischen Methode 'Factory' verwenden zu können.

Es gibt keine Einschränkung für einen Konstruktor mit Parametern. Es werden nur parameterlose Konstruktoren unterstützt.

Typschluss (Klassen)

Entwickler können durch die Tatsache herausgefunden werden, dass die Typinferenz für Konstruktoren nicht funktioniert :

class Tuple<T1,T2>
{
   public Tuple(T1 value1, T2 value2)
   {
   }
}

var x = new Tuple(2, "two");              // This WON'T work...
var y = new Tuple<int, string>(2, "two"); // even though the explicit form will.

Die erste Möglichkeit, eine Instanz ohne explizite Angabe von Typparametern zu erstellen, führt zu einem Fehler bei der Kompilierung, der Folgendes besagt:

Die Verwendung des generischen Typs 'Tuple <T1, T2>' erfordert zwei Typargumente

Eine häufige Problemumgehung ist das Hinzufügen einer Hilfsmethode in einer statischen Klasse:

static class Tuple
{
    public static Tuple<T1, T2> Create<T1, T2>(T1 value1, T2 value2)
    {
         return new Tuple<T1, T2>(value1, value2);
    }
}

var x = Tuple.Create(2, "two");  // This WILL work...

Reflektieren von Typparametern

Der Operator typeof arbeitet mit Typparametern.

class NameGetter<T>
{
    public string GetTypeName()
    {
        return typeof(T).Name;
    }
}

Explizite Typparameter

Es gibt verschiedene Fälle, in denen Sie die Typparameter für eine generische Methode explizit angeben müssen. In den beiden folgenden Fällen kann der Compiler nicht alle Typparameter aus den angegebenen Methodenparametern ableiten.

Ein Fall ist, wenn es keine Parameter gibt:

public void SomeMethod<T, V>() 
{
   // No code for simplicity
}

SomeMethod(); // doesn't compile
SomeMethod<int, bool>(); // compiles

Der zweite Fall ist, wenn einer (oder mehrere) der Typparameter nicht Teil der Methodenparameter ist:

public K SomeMethod<K, V>(V input)
{
    return default(K);
}

int num1 = SomeMethod(3); // doesn't compile
int num2 = SomeMethod<int>("3"); // doesn't compile
int num3 = SomeMethod<int, string>("3"); // compiles.

Verwendung einer generischen Methode mit einer Schnittstelle als Einschränkungstyp.

Dies ist ein Beispiel für die Verwendung der generischen Methode TFood inside Eat für die Klasse Animal

public interface IFood
{
    void EatenBy(Animal animal);
}

public class Grass: IFood
{
    public void EatenBy(Animal animal)
    {
        Console.WriteLine("Grass was eaten by: {0}", animal.Name);
    }
}

public class Animal
{
    public string Name { get; set; }

    public void Eat<TFood>(TFood food)
        where TFood : IFood
    {
        food.EatenBy(this);
    }
}

public class Carnivore : Animal
{
    public Carnivore()
    {
        Name = "Carnivore";
    }
}

public class Herbivore : Animal, IFood
{
    public Herbivore()
    {
        Name = "Herbivore";
    }
    
    public void EatenBy(Animal animal)
    {
        Console.WriteLine("Herbivore was eaten by: {0}", animal.Name);
    }
}

Sie können die Eat-Methode folgendermaßen aufrufen:

var grass = new Grass();        
var sheep = new Herbivore();
var lion = new Carnivore();
    
sheep.Eat(grass);
//Output: Grass was eaten by: Herbivore

lion.Eat(sheep);
//Output: Herbivore was eaten by: Carnivore

In diesem Fall, wenn Sie versuchen anzurufen:

sheep.Eat(lion);

Dies ist nicht möglich, da der Objektlöwe die Schnittstelle IFood nicht implementiert. Wenn Sie versuchen, den obigen Aufruf auszuführen, wird ein Compiler-Fehler generiert: "Der Typ 'Carnivore' kann nicht als Typparameter 'TFood' in der generischen Art oder Methode 'Animal.Eat (TFood)' verwendet werden. Es gibt keine implizite Referenzkonvertierung von ' Fleischfresser 'zu' IFood '. "

Kovarianz

Wann ist ein IEnumerable<T> ein Subtyp eines anderen IEnumerable<T1> ? Wenn T ein Untertyp von T1 . IEnumerable ist in seinem T Parameter kovariant , was bedeutet, dass die Subtyp-Beziehung von IEnumerable in dieselbe Richtung geht wie die von T

class Animal { /* ... */ }
class Dog : Animal { /* ... */ }

IEnumerable<Dog> dogs = Enumerable.Empty<Dog>();
IEnumerable<Animal> animals = dogs;  // IEnumerable<Dog> is a subtype of IEnumerable<Animal>
// dogs = animals;  // Compilation error - IEnumerable<Animal> is not a subtype of IEnumerable<Dog>

Eine Instanz eines kovarianten generischen Typs mit einem bestimmten Typparameter ist implizit in denselben generischen Typ mit einem weniger abgeleiteten Typparameter konvertierbar.

Diese Beziehung hält , weil IEnumerable produziert T s sie aber nicht verbrauchen. Ein Objekt , das erzeugt Dog s kann verwendet werden , als ob es produziert Animal s.

Covariante Typparameter werden mit dem Schlüsselwort out deklariert, da der Parameter nur als Ausgabe verwendet werden muss .

interface IEnumerable<out T> { /* ... */ }

Ein als kovariant deklarierter Typparameter wird möglicherweise nicht als Eingabe angezeigt.

interface Bad<out T>
{
    void SetT(T t);  // type error
}

Hier ist ein vollständiges Beispiel:

using NUnit.Framework;

namespace ToyStore
{
   enum Taste { Bitter, Sweet };

   interface IWidget
   {
      int Weight { get; }
   }

   interface IFactory<out TWidget>
       where TWidget : IWidget
   {
      TWidget Create();
   }

   class Toy : IWidget
   {
      public int Weight { get; set; }
      public Taste Taste { get; set; }
   }

   class ToyFactory : IFactory<Toy>
   {
      public const int StandardWeight = 100;
      public const Taste StandardTaste = Taste.Sweet;

      public Toy Create() { return new Toy { Weight = StandardWeight, Taste = StandardTaste }; }
   }

   [TestFixture]
   public class GivenAToyFactory
   {
      [Test]
      public static void WhenUsingToyFactoryToMakeWidgets()
      {
         var toyFactory = new ToyFactory();

         //// Without out keyword, note the verbose explicit cast:
         // IFactory<IWidget> rustBeltFactory = (IFactory<IWidget>)toyFactory;

         // covariance: concrete being assigned to abstract (shiny and new)
         IFactory<IWidget> widgetFactory = toyFactory;
         IWidget anotherToy = widgetFactory.Create();
         Assert.That(anotherToy.Weight, Is.EqualTo(ToyFactory.StandardWeight)); // abstract contract
         Assert.That(((Toy)anotherToy).Taste, Is.EqualTo(ToyFactory.StandardTaste)); // concrete contract
      }
   }
}

Verstöße

Wann ist ein IComparer<T> ein Subtyp eines anderen IComparer<T1> ? Wenn T1 ein Subtyp von T . IComparer ist in seinem T Parameter kontravariant , was bedeutet, dass die Untertypenbeziehung von IComparer in die entgegengesetzte Richtung geht wie T

class Animal { /* ... */ }
class Dog : Animal { /* ... */ }

IComparer<Animal> animalComparer = /* ... */;
IComparer<Dog> dogComparer = animalComparer;  // IComparer<Animal> is a subtype of IComparer<Dog>
// animalComparer = dogComparer;  // Compilation error - IComparer<Dog> is not a subtype of IComparer<Animal>

Eine Instanz eines kontravarianten generischen Typs mit einem bestimmten Typparameter ist implizit in denselben generischen Typ mit einem stärker abgeleiteten Typparameter konvertierbar.

Diese Beziehung hält , weil IComparer verbraucht T s sie aber nicht produzieren. Ein Objekt, das zwei beliebige Animal miteinander vergleichen kann, kann zum Vergleichen zweier Dog .

Kontravariante Typparameter werden mit dem Schlüsselwort in deklariert, da der Parameter nur als Eingabe verwendet werden muss .

interface IComparer<in T> { /* ... */ }

Ein als widerspruchsfrei deklarierter Typparameter wird möglicherweise nicht als Ausgabe angezeigt.

interface Bad<in T>
{
    T GetT();  // type error
}

Invarianz

IList<T> ist niemals ein Subtyp einer anderen IList<T1> . IList ist in ihrem Typparameter invariant .

class Animal { /* ... */ }
class Dog : Animal { /* ... */ }

IList<Dog> dogs = new List<Dog>();
IList<Animal> animals = dogs;  // type error

Es gibt keine Untertypenbeziehung für Listen, da Sie Werte in eine Liste aufnehmen und Werte aus einer Liste entnehmen können.

Wenn IList kovariant war, können Sie der angegebenen Liste Elemente des falschen Untertyps hinzufügen.

IList<Animal> animals = new List<Dog>();  // supposing this were allowed...
animals.Add(new Giraffe());  // ... then this would also be allowed, which is bad!

Wenn IList , können Sie Werte aus einem bestimmten Untertyp aus einer bestimmten Liste extrahieren.

IList<Dog> dogs = new List<Animal> { new Dog(), new Giraffe() };  // if this were allowed...
Dog dog = dogs[1];  // ... then this would be allowed, which is bad!

Invariant Typ - Parameter werden durch Weglassen sowohl die erklärt in und out Schlüsselwörtern.

interface IList<T> { /* ... */ }

Variantenschnittstellen

Schnittstellen können Variantentyp-Parameter haben.

interface IEnumerable<out T>
{
    // ...
}
interface IComparer<in T>
{
    // ...
}

Klassen und Strukturen dürfen jedoch nicht

class BadClass<in T1, out T2>  // not allowed
{
}

struct BadStruct<in T1, out T2>  // not allowed
{
}

auch keine generischen Methodendeklarationen

class MyClass
{
    public T Bad<out T, in T1>(T1 t1)  // not allowed
    {
        // ...
    }
}

Das folgende Beispiel zeigt mehrere Abweichungsdeklarationen auf derselben Schnittstelle

interface IFoo<in T1, out T2, T3>
//  T1 : Contravariant type
//  T2 : Covariant type 
//  T3 : Invariant type
{
    // ...
}

IFoo<Animal, Dog, int> foo1 = /* ... */;
IFoo<Dog, Animal, int> foo2 = foo1;  
// IFoo<Animal, Dog, int> is a subtype of IFoo<Dog, Animal, int>

Variantendelegierte

Delegierte können Variantentypparameter haben.

delegate void Action<in T>(T t);    // T is an input
delegate T Func<out T>();           // T is an output
delegate T2 Func<in T1, out T2>();  // T1 is an input, T2 is an output

Dies folgt aus dem Liskov-Substitutionsprinzip , das unter anderem festlegt , dass eine Methode D als abgeleiteter angesehen werden kann als eine Methode B, wenn:

  • D hat einen gleichen oder mehr abgeleiteten Rückgabetyp als B
  • D hat gleiche oder allgemeinere entsprechende Parametertypen als B

Daher sind die folgenden Zuweisungen alle typsicher:

Func<object, string> original = SomeMethod;
Func<object, object> d1 = original;
Func<string, string> d2 = original;
Func<string, object> d3 = original;

Variantentypen als Parameter und Rückgabewerte

Wenn ein kovarianter Typ als Ausgabe angezeigt wird, ist der enthaltende Typ kovariant. Die Herstellung eines Produzenten von T ist wie das Herstellen von T .

interface IReturnCovariant<out T>
{
    IEnumerable<T> GetTs();
}

Wenn ein kontravarianter Typ als Ausgabe angezeigt wird, ist der enthaltende Typ kontravariant. Einen Konsumenten von T ist wie der Konsum von T .

interface IReturnContravariant<in T>
{
    IComparer<T> GetTComparer();
}

Wenn ein kovarianter Typ als Eingabe erscheint, ist der enthaltende Typ kontravariant. Der Konsum eines Produzenten von T ist wie der Konsum von T .

interface IAcceptCovariant<in T>
{
    void ProcessTs(IEnumerable<T> ts);
}

Wenn ein kontravarianter Typ als Eingabe erscheint, ist der enthaltende Typ kovariant. Ein Konsument von T konsumieren ist wie das Produzieren von T .

interface IAcceptContravariant<out T>
{
    void CompareTs(IComparer<T> tComparer);
}

Gleichheit der generischen Werte prüfen.

Wenn die Logik einer generischen Klasse oder Methode die Überprüfung der Gleichheit von Werten mit generischem Typ erfordert, verwenden Sie EqualityComparer<TType>.Default Eigenschaft :

public void Foo<TBar>(TBar arg1, TBar arg2)
{
    var comparer = EqualityComparer<TBar>.Default;
    if (comparer.Equals(arg1,arg2)
    {
        ...
    }
}

Dieser Ansatz ist besser als der Aufruf der Object.Equals() -Methode, da die Standardvergleichsimplementierung prüft, ob der TBar Typ die IEquatale<TBar> Schnittstelle IEquatale<TBar> implementiert, und wenn ja, die IEquatable<TBar>.Equals(TBar other) -Methode. Dadurch kann das Boxen / Unboxing von Werttypen vermieden werden.

Generisches Gussteil

    /// <summary>
    /// Converts a data type to another data type.
    /// </summary>
    public static class Cast
    {
        /// <summary>
        /// Converts input to Type of default value or given as typeparam T
        /// </summary>
        /// <typeparam name="T">typeparam is the type in which value will be returned, it could be any type eg. int, string, bool, decimal etc.</typeparam>
        /// <param name="input">Input that need to be converted to specified type</param>
        /// <param name="defaultValue">defaultValue will be returned in case of value is null or any exception occures</param>
        /// <returns>Input is converted in Type of default value or given as typeparam T and returned</returns>
        public static T To<T>(object input, T defaultValue)
        {
            var result = defaultValue;
            try
            {
                if (input == null || input == DBNull.Value) return result;
                if (typeof (T).IsEnum)
                {
                    result = (T) Enum.ToObject(typeof (T), To(input, Convert.ToInt32(defaultValue)));
                }
                else
                {
                    result = (T) Convert.ChangeType(input, typeof (T));
                }
            }
            catch (Exception ex)
            {
                Tracer.Current.LogException(ex);
            }

            return result;
        }
        
        /// <summary>
        /// Converts input to Type of typeparam T
        /// </summary>
        /// <typeparam name="T">typeparam is the type in which value will be returned, it could be any type eg. int, string, bool, decimal etc.</typeparam>
        /// <param name="input">Input that need to be converted to specified type</param>
        /// <returns>Input is converted in Type of default value or given as typeparam T and returned</returns>
        public static T To<T>(object input)
        {
            return To(input, default(T));
        }

        

    }

Verbrauch:

std.Name = Cast.To<string>(drConnection["Name"]);
std.Age = Cast.To<int>(drConnection["Age"]);
std.IsPassed = Cast.To<bool>(drConnection["IsPassed"]);


// Casting type using default value
//Following both ways are correct
// Way 1 (In following style input is converted into type of default value)
std.Name = Cast.To(drConnection["Name"], "");
std.Marks = Cast.To(drConnection["Marks"], 0);
// Way 2    
std.Name = Cast.To<string>(drConnection["Name"], "");
std.Marks = Cast.To<int>(drConnection["Marks"], 0);

Konfigurationsleser mit generischem Typ Casting

    /// <summary>
    /// Read configuration values from app.config and convert to specified types
    /// </summary>
    public static class ConfigurationReader
    {
        /// <summary>
        /// Get value from AppSettings by key, convert to Type of default value or typeparam T and return
        /// </summary>
        /// <typeparam name="T">typeparam is the type in which value will be returned, it could be any type eg. int, string, bool, decimal etc.</typeparam>
        /// <param name="strKey">key to find value from AppSettings</param>
        /// <param name="defaultValue">defaultValue will be returned in case of value is null or any exception occures</param>
        /// <returns>AppSettings value against key is returned in Type of default value or given as typeparam T</returns>
        public static T GetConfigKeyValue<T>(string strKey, T defaultValue)
        {
            var result = defaultValue;
            try
            {
                if (ConfigurationManager.AppSettings[strKey] != null)
                    result = (T)Convert.ChangeType(ConfigurationManager.AppSettings[strKey], typeof(T));
            }
            catch (Exception ex)
            {
                Tracer.Current.LogException(ex);
            }

            return result;
        }
        /// <summary>
        /// Get value from AppSettings by key, convert to Type of default value or typeparam T and return
        /// </summary>
        /// <typeparam name="T">typeparam is the type in which value will be returned, it could be any type eg. int, string, bool, decimal etc.</typeparam>
        /// <param name="strKey">key to find value from AppSettings</param>
        /// <returns>AppSettings value against key is returned in Type given as typeparam T</returns>
        public static T GetConfigKeyValue<T>(string strKey)
        {
            return GetConfigKeyValue(strKey, default(T));
        }

    }

Verbrauch:

var timeOut = ConfigurationReader.GetConfigKeyValue("RequestTimeout", 2000);
var url = ConfigurationReader.GetConfigKeyValue("URL", "www.someurl.com");
var enabled = ConfigurationReader.GetConfigKeyValue("IsEnabled", false);


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow