2011-06-13 7 views
0

J'ai un objet "ConnectableProperty" qui relie une propriété à une autre, et nécessite que je l'alimente Func. Maintenant, j'ai 2 types en ce moment - Scalaire et Couleur. Les deux sont transposables les uns aux autres via des opérateurs explicites. Pour une raison quelconque, je ne peux pas envoyer un Func<double, double, Scalar> à Func<double, double Color>, même si Scalar peut utiliser la couleur. Quel est le problème?Méthode anonyme de retour de type casting

Pour clarifier, j'ai ajouté le code. Notez que les propriétés connectables sont les "entrées". Les sorties (qui peuvent être branchées) sont des méthodes qui ont cette signature.

Voilà ConnectableProperty

public sealed class ConnectableProperty<T> : IEquatable<T>, IGetXY<T> where T : IValue<T> 
{ 
    private T _value; 
    public T Value { get { return _value; } set { _value = value; } } 

    public INode ParentNode { get; private set; } 
    public ValueConnection<T> Connection { get; set; } 
    public INode ConnectionFrom { get { return !IsConnected ? null : Connection.FromNode; } } 
    public bool IsConnected { get { return Connection == null; } } 

    public ConnectableProperty(INode parentNode, T value) 
    { 
     ParentNode = parentNode; 
     _value = value; 
    } 

    public T GetXY(double x, double y) 
    { 
     return IsConnected 
      ? Connection.FromValue(x, y) 
      : _value; 
    } 

    public void Connect(INode fromNode, Func<double, double, T> getXY) 
    { 
     Connection = new ValueConnection<T>(fromNode, ParentNode, getXY, this); 
    } 

    public void Disconnect() 
    { 
     Connection = null; 
    } 

    public bool Equals(T other) 
    { 
     return _value.Equals(other); 
    } 

    public static implicit operator T(ConnectableProperty<T> connectableProperty) 
    { 
     return connectableProperty._value; 
    } 
} 

Et ValueConnection:

public class ValueConnection<T> 
{ 
    public INode FromNode { get; private set; } 
    public INode ToNode { get; private set; } 

    public Func<double, double, T> FromValue { get; private set; } 
    public ConnectableProperty<T> ToValue { get; private set; } 

    public ValueConnection(INode fromNode, INode toNode, Func<double, double, T> fromValue, ConnectableProperty<T> toValue) 
    { 
     // TODO: Implement INPC type thing 

     FromNode = fromNode; 
     ToNode = toNode; 

     FromValue = fromValue; 
     ToValue = toValue; 
    } 
} 
+0

Pouvez-vous donner un exemple de la façon dont vous le faites en ce moment? –

+0

Pouvez-vous poster vos objets? Si la distribution n'est possible que explicitement, je ne vois pas comment le Func peut fonctionner. – IndigoDelta

+0

peut-être s'il y avait une sorte d'héritage, ou une implémentation d'interface, vous pourriez alimenter la fonction scalaire à la couleur, mais pas comme ça – Atzoya

Répondre

5

Non, vous ne serez pas en mesure d'effectuer cette conversion directement, et je ne voudrais pas attendre de pouvoir - mais vous pourrait facilement écrire une paire de méthodes pour l'effectuer pour vous:

public Func<double, double, Scalar> ConvertFunc(Func<double, double, Color func) 
{ 
    return (x, y) => (Scalar) func(x, y); 
} 

public Func<double, double, Color> ConvertFunc(Func<double, double, Scalar func) 
{ 
    return (x, y) => (Color) func(x, y); 
} 

Quand vous avez un délégué qui est destiné à renvoyer un type particulier, qui doit pouvoir être appelé directement et renvoyer une valeur du type approprié. L'appelant ne devrait pas avoir à savoir que, même s'il a un Func<X>, s'il veut obtenir un X, il devra convertir le résultat en X.

+0

Peut-on simplement déclarer son propre type 'Func' et spécifier que le paramètre du troisième type est 'out' (covariance). Cela fonctionnerait-il? –

+0

@zespri: Le paramètre résultat de 'Func ' est déjà covariant dans .NET 4, mais la covariance ne fonctionne pas avec les conversions définies par l'utilisateur. –

+0

prend tout son sens. Je vous remercie. –

0

Vous ne feriez pas le travail simplement en utilisant un cast explicite à l'intérieur du corps de la fonction? Alors vous pouvez utiliser un seul type de la fonction - pas besoin de lancer

6

Jon a raison; Juste pour ajouter à cela:

Tout d'abord, la raison pour laquelle cela ne fonctionne pas est parce qu'il n'y a pas d'endroit où la conversion existe. Supposons que vous ayez:

Func<int> f1 =()=>1; 
Func<double> f2 = f1; 

Supposons que cela soit légal. Quelque part, le compilateur C# doit générer une instruction qui convertit un int en un double. Où? Pas dans le lambda; cette chose doit retourner un int quand f1 est appelé. Mais pas dans f2 non plus, car f1 est référence identique à f1. Il existe deux solutions possibles: le rendre illégal, ou faire cela signifie réellement:

f2 =()=>(double)f1(); 

de sorte que f1 et f2 ne sont pas référence identiques plus. Nous avons choisi la première solution.

Deuxièmement, ceci est légal en C# 4 si les types de retour ont une conversion implicite référence entre eux. Nous n'avons pas besoin d'émettre d'instructions pour une conversion de référence implicite; c'est légal sans aucun code spécial.

Questions connexes