web-dev-qa-db-fra.com

Conversion DateTime nullable

Duplicata possible:
c # pourquoi ne peut-on pas affecter un nullable int comme valeur

Im essayant de convertir mon objet reader [3] qui est datetime pour être nul s'il n'y a pas de lastPostDate pour un forum mais il dit qu'il manque une conversion. Erreur:

Le type d'expression conditionnelle ne peut pas être déterminé car il n'y a pas de conversion implicite entre <null> et 'System.DateTime'

public class Forums
{
    public List<Forum> GetForums()
    {
        using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["CMS"].ConnectionString))
        {
            conn.Open();
            SqlCommand cmd = new SqlCommand("sproc_Forums_GetForums", conn);
            cmd.CommandType = CommandType.StoredProcedure;
            SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.Default);

            List<Forum> forums = new List<Forum>();
            while (reader.Read())
            {
                var title = reader[6].ToString();
                var threadCount = (int)reader[5];
                var lastPostTitle = reader[4].ToString();
                // below is where im having a problem
                Nullable<DateTime> lastPostDate = (reader[3] == DBNull.Value ? null : Convert.ToDateTime(reader[3])); 
                var lastPostBy = reader[2].ToString();
                var forumGroup = reader[1].ToString();
                var description = reader[0].ToString();

                Forum forum = new Forum(0, "",DateTime.Now,
                    reader["Title"].ToString(),description,
                    0,false,"","",DateTime.Now,true,
                    forumGroup, (int)threadCount, lastPostBy,
                    lastPostDate, lastPostTitle);
                forums.Add(forum);/**/

            }
            return forums;

        }

    }            
}

Ci-dessous, mon objet de classe pour Forum avec un Nullable lastPostDate

    public class Forum
{
    public Forum(int forumID, string addedBy, DateTime addedDate, string title, string description, int parentID, bool moderated,
        string imageUrl, string updatedBy, DateTime? updatedDate, bool active, string forumGroup, int threadCount, string lastPostBy,
        Nullable<DateTime> lastPostDate, string lastPostTitle)
    {
        this.ForumID = forumID;
        this.AddedBy = addedBy;
        this.AddedDate = addedDate;
        this.Title = title;
        this.Description = description;
        this.ParentID = parentID;
        this.Moderated = moderated;
        this.ImageUrl = imageUrl;
        this.UpdatedBy = updatedBy;
        this.UpdatedDate = updatedDate;
        this.Active = active;
        this.ForumGroup = forumGroup;
        this.ThreadCount = threadCount;
        this.LastPostBy = lastPostBy;
        this.LastPostDate = lastPostDate;
        this.LastPostTitle = lastPostTitle;
    }

    private int _forumID;
    public int ForumID
    {
        get { return _forumID; }
        set { _forumID = value; }
    }
    private string _addedBy;
    public string AddedBy
    {
        get { return _addedBy; }
        set { _addedBy = value; }
    }
    private DateTime _addedDate = DateTime.Now;
    public DateTime AddedDate
    {
        get { return _addedDate; }
        set { _addedDate = value; }
    }
    private string _title = "";
    public string Title
    {
        get { return _title; }
        set { _title = value; }
    }
    private string _description = "";
    public string Description
    {
        get { return _description; }
        set { _description = value; }
    }
    private int _parentID = 0;
    public int ParentID
    {
        get { return _parentID; }
        set { _parentID = value; }
    }
    private bool _moderated = false;
    public bool Moderated
    {
        get { return _moderated; }
        set { _moderated = value; }
    }
    private string _imageUrl = "";
    public string ImageUrl
    {
        get { return _imageUrl; }
        set { _imageUrl = value; }
    }
    private string _updatedBy = "";
    public string UpdatedBy
    {
        get { return _updatedBy; }
        set { _updatedBy = value; }
    }
    private DateTime? _updatedDate = null;
    public DateTime? UpdatedDate
    {
        get { return _updatedDate; }
        set { _updatedDate = value; }
    }
    private bool _active = false;
    public bool Active
    {
        get { return _active; }
        set { _active = value; }
    }
    private string _forumGroup = "";
    public string ForumGroup
    {
        get { return _forumGroup; }
        set { _forumGroup = value; }
    }
    private int _threadCount = 0;
    public int ThreadCount
    {
        get { return _threadCount; }
        set { _threadCount = value; }
    }
    private string _lastPostBy = "";
    public string LastPostBy
    {
        get { return _lastPostBy; }
        set { _lastPostBy = value; }
    }
    private Nullable<DateTime> _lastPosteDate = null;
    public Nullable<DateTime> LastPostDate
    {
        get { return _lastPosteDate; }
        set { _lastPosteDate = value; }
    }
    private string _lastPostTitle = "";
    public string LastPostTitle
    {
        get { return _lastPostTitle; }
        set { _lastPostTitle = value; }
    }
}
26
ONYX

Vous voudrez peut-être le faire comme ceci:

DateTime? lastPostDate =  (DateTime?)(reader.IsDbNull(3) ? null : reader[3]); 

Le problème que vous rencontrez est que l'opérateur ternaire veut une distribution viable entre les côtés gauche et droit. Et null ne peut pas être casté en DateTime.

Notez les travaux ci-dessus car les deux côtés du ternaire appartiennent à l'objet. L'objet est explicitement casté en DateTime? qui fonctionne: tant que le lecteur [3] est en fait une date.

28
jmoreno

Assurez-vous que ces deux types sont nullable DateTime

var lastPostDate = reader[3] == DBNull.Value ?
                                        null : 
                                   (DateTime?) Convert.ToDateTime(reader[3]);
  • L'utilisation de DateTime? au lieu de Nullable<DateTime> est un gain de temps ...
  • Utilisez un meilleur retrait du? expression comme je l'ai fait.

J'ai trouvé ces excellentes explications dans Eric Lippert blog :

La spécification de ?: L'opérateur indique ce qui suit:

Les deuxième et troisième opérandes de l'opérateur?: Contrôlent le type de l'expression conditionnelle. Soit X et Y les types des deuxième et troisième opérandes. Ensuite,

  • Si X et Y sont du même type, alors c'est le type de l'expression conditionnelle.

  • Sinon, s'il existe une conversion implicite de X en Y, mais pas de Y en X, alors Y est le type de l'expression conditionnelle.

  • Sinon, s'il existe une conversion implicite de Y en X, mais pas de X en Y, alors X est le type de l'expression conditionnelle.

  • Sinon, aucun type d'expression ne peut être déterminé et une erreur de compilation se produit.

Le compilateur ne vérifie pas quel type peut "contenir" ces deux types.

Dans ce cas:

  • null et DateTime ne sont pas du même type.
  • null n'a pas de conversion implicite en DateTime
  • DateTime n'a pas de conversion implicite en null

Nous nous retrouvons donc avec une erreur de compilation.

27
gdoron

Castez le littéral nul: (DateTime?)null Ou (Nullable<DateTime>)null.

Vous pouvez également utiliser default(DateTime?) ou default(Nullable<DateTime>)

Et, comme d'autres réponses l'ont noté, vous pouvez également appliquer le transtypage à la valeur DateTime plutôt qu'au littéral null.

EDIT (adapté de mon commentaire à la réponse de Prutswonder):

Le fait est que l'opérateur conditionnel ne prend pas en compte le type de sa cible d'affectation, il ne compilera donc que s'il y a une conversion implicite du type de son deuxième opérande au type de son troisième opérande, ou du type de son troisième opérande au type de son deuxième opérande.

Par exemple, cela ne compilera pas:

bool b = GetSomeBooleanValue();
object o = b ? "Forty-two" : 42;

Toutefois, la conversion du deuxième ou du troisième opérande en object résout le problème, car il existe une conversion implicite d'int en objet et également de chaîne en objet:

object o = b ? "Forty-two" : (object)42;

ou

object o = b ? (object)"Forty-two" : 42;
8
phoog

Vous pouvez essayer ceci

var lastPostDate = reader[3] == DBNull.Value ?
                                default(DateTime?): 
                                Convert.ToDateTime(reader[3]);
5
Amar Palsapure