2011-05-08 1 views
2

Considérant une méthode générique, est-il possible de définir une contrainte sur le type de modèle pour avoir des propriétés spécifiques?Propriété requise dans un type de modèle en C#

Pour compiler avec succès le code suivant par exemple

public static int[] DoSomething<T> (T[] Input) 
{ 
    int[] Output = new int[Input.Length]; 

    for (int i = 0;i < Input.Length;i++) 
     Output[i] = (int)Input[i].PropertyA+(int)Input[i].PropertyB; 

    return Output; 
} 

le type de modèle doit mettre en œuvre le PropertyA et PropertyB. Est-il possible de définir une telle contrainte sur le type de modèle?

EDIT: et exigent en outre que PropertyA et PropertyB soient les types numériques afin qu'ils puissent être tapés int.

Merci.

Répondre

5

La seule possibilité est de définir T comme type dérivé d'une certaine classe de base bien connue ou mise en œuvre de l'interface bien connue:

public interface IWellKnown 
{ 
    int PropertyA { get; } 
    int PropertyB { get; } 
} 

Toute méthode sera:

public static int[] DoSomething<T> (T[] Input) where T : IWellKnown 
{ 
    int[] Output = new int[Input.Length]; 

    for (int i = 0;i < Input.Length;i++) 
     Output[i] = Input[i].PropertyA+Input[i].PropertyB; 

    return Output; 
} 

Edit:

La création d'une méthode générique fonctionnant avec n'importe quel type numérique mais avec des types numériques est imho impossible car .NET n'a aucun type de base commedix . Vous ne pouvez donc pas limiter le type générique aux nombres uniquement. Tous les types numériques sont des types de valeur de sorte que vous pouvez faire quelque chose comme:

public interface IWellKnown<TData> where TData : struct 
{ 
    TData PropertyA { get; } 
    TData PropertyB { get; } 
} 

Mais dans ce cas, l'interface accepte tout type de valeur - une structure personnalisée, char, bool, etc.

+0

Oui, vous avez raison, mais que se passe-t-il si j'ai besoin que ces propriétés soient généralement numériques, pas nécessairement des entiers. J'ai mal posé la question, désolé. Mais merci pour votre réponse de toute façon. – NumberFour

0

Ce ne est pas possible créer une telle restriction. Vous devriez vérifier l'entrée à l'exécution et lancer un message d'erreur d'exception utile.

Vous pouvez cependant faire quelque chose comme:

public interface IWellKnown 
{ 
    int PropertyA { get; } 
    int PropertyB { get; } 
} 

public abstract class WellKnownBase<T> : IWellKnown 
{ 
    IWellKnown.PropertyA { get { return Convert(this.PropertyA); } } 
    IWellKnown.PropertyB { get { return Convert(this.PropertyB); } } 

    public T PropertyA { get; } 
    public T PropertyA { get; } 

    protected virtual int Convert(T input) { return (int)input; } 
} 

En utilisant une telle classe de base guides d'une mise en œuvre d'une version concrète de fournir un moyen de jeter à int. L'implémentation d'interface explicite donne accès à des accesseurs typés int tandis que la classe "real" fournit toujours le type d'origine.

public class WellKnownFloat : WellKnownBase<Float> {} 

Vous obtiendriez une classe pour float. Si le type ne peut être converti int vous pouvez fournir un convertisseur de mesure:

public class WellKnownTimeSpan : WellKnownBase<TimeSpan> 
{ 
    protected override int Convert(TimeSpan input) 
    { 
     return (int)input.TotalMilliseconds; 
    } 
} 

Soit dit en passant, en utilisant LINQ et en ajoutant l'exigence de l'interface, vous pouvez réécrire votre fonction input.Select(x => x.PropertyA + x.PropertyB)).ToArray(). PS: s'il vous plaît vérifier le code en utilisant VisualStudio, je l'écris juste hors de ma tête sans support du compilateur;) Il peut y avoir de petites erreurs compiletime.

Questions connexes