Est-il possible de définir une variable c # avec une valeur de type de variable différente de celle définie par la variable?
public class Test{
public DateTime TimeSinceEpoch {
get {return TimeSinceEpoch; }
set{
DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
TimeSinceEpoch = Epoch.AddMilliseconds(value);}} //<-the value that's expected is a DateTime value..
}
Comment puis-je écrire: «TimeSinceEpoch = 1549090800000» et utiliser TimeSinceEpoch comme variable DateTime normale?
Sans avoir à séparer les variables get et set dans la classe
5 Réponses :
Vous avez besoin d'une variable privée pour DateTime et d'une propriété longue. Voir le code ci-dessous:
public class Test
{
private DateTime Epoch { get;set; }
public long TimeSinceEpoch {
get {return Epoch.Ticks; }
set{
DateTime temp = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
Epoch = temp.AddMilliseconds(value);
}
}
}
Cela échoue à l'objectif «et utiliser TimeSinceEpoch comme un objectif DateTime normal» indiqué dans la question.
Le code n'est qu'un exemple et nécessite quelques modifications mineures. Je viens de publier la variable privée manquante. Je sais que le code tel que publié ne va pas convertir correctement l'heure Unix en heure Windows.
Vous pouvez simplement l'utiliser comme vous le faites et pour obtenir des millisecondes:
TimeSinceEpoch = DateTime.Now; var ms = TimeSinceEpoch.MilliSeccondsSinceEpoch();
ou peut-être créer une méthode d'extension pour cela comme:
public static class Extensions
{
public static long MilliSeccondsSinceEpoch(this DateTime d)
{
DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
return (d - Epoch).TotalMillisecond;
}
}
Ensuite, vous pouvez l'utiliser comme:
var ms = (TimeSinceEpoch - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalMilliSeconds;
Ceci n'est pas autorisé même en C ++ / CLI qui a une syntaxe pour cela:
struct SuperDateTime
{
public DateTime Value;
public static implicit operator SuperDateTime(DateTime d) { return new SuperDateTime { Value = d }; }
public static implicit operator SuperDateTime(long x) { return new SuperDateTime { Value = Epoch.AddMilliseconds(x) }; }
public static implicit operator DateTime(SuperDateTime d) { return d.Value; }
}
Vous obtenez l'erreur suivante:
erreur C3902: 'set': le type du dernier paramètre doit être 'System :: DateTime'
Intellisense produit en fait deux plaintes, selon l'ordre dans lequel vous les écrivez:
E1930: un accesseur 'set' a déjà été déclaré pour cette propriété à
ou
E1942: le dernier paramètre de l'accesseur 'set' ne correspond pas au type de propriété
Le problème sous-jacent est qu'une propriété .NET doit lister un type et un maximum d'un setter dans les métadonnées (Jetez un œil à PropertyInfo.GetSetMethod - il en renvoie un setter ou null , pas un tableau). Même si vous pouvez facilement surcharger la fonction setter elle-même:
void set_TimeSinceEpoch(DateTime) void set_TimeSinceEpoch(long)
une seule de ces deux fonctions peut être associée à la propriété.
Vous pouvez utiliser un type d'assistance pour autoriser plusieurs types entrants:
public ref struct Test
{
property System::DateTime TimeSinceEpoch
{
DateTime get();
void set(DateTime);
void set(long long);
}
};
mais cela cassera les lecteurs de la propriété, qui doivent maintenant dire TimeSinceEpoch.Value avant d'utiliser un membre (s'il est passé en argument à une autre fonction, la conversion implicite se déclenchera). Pour surmonter cela, vous devez écrire une fonction de transfert pour chaque membre DateTime .
Le code suivant fonctionne comme je le souhaitais. J'espère que cela aide quelqu'un d'autre
Cela échoue à l'objectif «et utiliser Time_Since_Epoch comme date et heure normale» indiqué dans la question, car toute personne lisant la propriété devra appliquer un cast.
Votre montage n'a rien fait.
@BenVoigt: Le nouveau code utilise une variable (Time) et une propriété (TimeSinceEpoch) alors que le code d'origine n'avait qu'une propriété.
@jdweng: Le changement essentiel était de rendre la propriété de type System.Object . L'ajout du champ a corrigé la récursivité infinie mais n'a pas abordé le point principal de la question en aucune façon.
Regardez de plus près la solution et le code d'origine.
Vous pouvez y parvenir en utilisant des transtypages implicites:
DateTime foo = Epoch.Value.AddMilliseconds(12345);
Vous pouvez donc
DateTime foo = Epoch.AddMilliseconds(12345);
Cependant, il vaut probablement mieux convertir explicitement votre numéro à une date en utilisant une méthode utilitaire:
public static class Epoch
{
public static readonly DateTime Value {get;} = new DateTime(1970,1,1);
public static DateTime AddMilliseconds(ms)
=> Value.AddMilliseconds(ms);
}
Ainsi vous pouvez
public class Test
{
public EpochBasedDateTime TimeSinceEpoch {get; set;}
}
var test = new Test();
test.TimeSinceEpoch = 12345;
DateTime dt = test.TimeSinceEpoch;
ou
public struct EpochBasedDateTime
{
public EpochBasedDateTime(DateTime value) => Value = value;
public EpochBasedDateTime(int milliseconds)
: this(Epoch.addMilliseconds(milliseconds)
{
}
public static readonly DateTime Epoch = new DateTime(1970,1,1);
public DateTime Value {get;}
public static implicit operator EpochBasedDateTime (int milliseconds)
=> new EpochBasedDateTime(milliseconds);
public static implicit operator DateTime (EpochBasedDateTime date)
=> date.Value;
}
que voulez-vous définir
Time_Since_Epoch?Notez que votre code actuel a une récursion infinie. Cela n'empêchera pas en soi la compilation, mais il n'y a pas de variable de sauvegarde, juste une référence circulaire à la même propriété.
Pourquoi ne pas créer une autre méthode de classe appelée par exemple SetTimeSinceEpoch (longues millisecondes) qui effectue l'affectation que vous recherchez. N'utilisez pas = pour l'attribution directe, sauf si vous utilisez le même type.
Oui, je sais que le code actuel ne se compilera pas, ma question est de savoir s'il est possible de définir une variable avec un format de variable différent de celui de l'élément racine
@Steinar: En fait, vous ne posez pas de questions sur une variable, mais sur une propriété. Ça ne fait aucune différence. Vous pouvez le définir avec un type différent si une conversion implicite existe. Et en C #, pas autrement.
@BenVoigt Que voulez-vous dire par conversion implicite?
Les conversions implicites sont décrites ici: docs.microsoft.com/en-us/dotnet/csharp/programming-guide/typ es /… Ils peuvent être créés en utilisant
opérateur implicite, mais vous n'êtes pas l'auteur deDateTimeoulongpour que cette approche ne fonctionne pas ici.La conversion implicite est une conversion pour laquelle vous n'avez pas besoin de faire un cast (conversion) explicite . (par exemple:
int a = 5; float b = a;l'entier a est implicitement convertible en float sans que vous ayez besoin d'écrirefloat b = (float) a;)Si votre code a fonctionné. À quoi vous attendez-vous lorsque vous mettez un vrai DateTime sur le côté droit du signe =? Cela n’aurait plus de sens de faire cela. Par conséquent, votre idée ne peut pas être autorisée à moins que l'objet de droite ne puisse être implicitement converti en votre type de variable.
@MikeWodarczyk lorsque vous utilisez le
set, en tant que développeur, vous choisissez de définir ce à quoi vous voulez définir la propriété, on pourrait probablement résoudre ce problème en ayant des gestionnaires d'erreurs qui vérifient le type de variable envoyé la fonctionset"Est-ce possible" est une question valable, même si ce n'est pas (possible), donc je ne suis pas d'accord avec le vote négatif.