【问题标题】:Assigning primitive datatype directly to Custom Object using indirect cast in C#使用 C# 中的间接转换将原始数据类型直接分配给自定义对象
【发布时间】:2019-03-15 20:07:12
【问题描述】:

我创建了一个名为 Parameter 的类,它可以将通用值作为对象保存。参数对象还有一个与之关联的 Unit 对象,它可以提供有关度量单位的信息,以便在我的程序的其他地方进行转换。我想要做的是能够直接为类分配通用数据类型值,并让它使用间接转换来分配正确的内部参数。下面以类的简化结构为例:

/// <summary>
/// Class represnting a single parameter, which contains a value and a unit of measure
/// </summary>
public class Parameter
{
    #region Operators

    /// <summary>
    /// Conversion from Parameter to double
    /// </summary>
    static public implicit operator double(Parameter p)
    {
        return Convert.ToDouble(p.BaseValue);
    }

    /// <summary>
    /// Conversion from Parameter to int
    /// </summary>
    static public implicit operator int(Parameter p)
    {
        return Convert.ToInt32(p.BaseValue);
    }

    /// <summary>
    /// Conversion from Parameter to bool
    /// </summary>
    static public implicit operator bool(Parameter p)
    {
        return (bool)p.BaseValue;
    }

    /// <summary>
    /// Conversion from Parameter to DateTime
    /// </summary>
    static public implicit operator DateTime(Parameter p)
    {
        return (DateTime)p.BaseValue;
    }

    /// <summary>
    /// Conversion from Parameter to TimeSpan
    /// </summary>
    static public implicit operator TimeSpan(Parameter p)
    {
        return (TimeSpan)p.BaseValue;
    }

    #endregion

    #region Properties

    /// <summary>
    /// Gets/Sets the name label for the parameter
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// Gets/Sets the Unit object representing the current unit of measure for the parameter.
    /// </summary>
    public Unit CurrentUnit { get; set; }

    /// <summary>
    /// Gets/Sets the value for the parameter in terms of it's base unit of measure
    /// </summary>
    public object BaseValue { get; set; }

    /// <summary>
    /// Gets/Sets the value for the parameter in terms of it's converted unit of measure (depending on the currentUnit setting)
    /// </summary>
    public object UnitValue
    {
        get
        {
            // Perform unit conversion only if the value is numeric and the CurrentUnit value is not null
            if (!(this.CurrentUnit == null) && (this.BaseValue is double || this.BaseValue is int))
            {
                return Convert.ToDouble(this.BaseValue) * this.CurrentUnit.ConversionFactor;
            }
            else
            {
                return this.BaseValue;
            }
        }

        set
        {
            // Perform unit conversion only if the value is numeric and the CurrentUnit value is not null
            if (!(this.CurrentUnit == null) && (this.BaseValue is double || this.BaseValue is int))
            {
                this.BaseValue = Convert.ToDouble(value) / CurrentUnit.ConversionFactor;
            }
            else
            {
                this.BaseValue = value;
            }
        }
    }

    #endregion
}

查看代码的 Operators 区域,我目前有一些函数允许以以下方式将参数对象的当前值直接分配给 double、int、bool、DateTime 和 TimeSpan 对象:

Parameter foo;
double aNumber;

// This part works just fine
aNumber = foo;

但我还希望能够做到以下几点:

foo = aNumber;

据我了解,我必须初始化一个新版本的对象以将aNumber 的值分配给BaseValue 属性,然后返回新创建的对象。问题是我想保留当前实例的所有设置并简单地更新属性并将当前实例分配回自身(或其他方式)。但是由于隐式转换需要是静态方法,我不确定如何直接访问实例值以简单地对BaseValue 进行所需的编辑并返回。有没有其他方法可以在不使用更复杂语法的情况下解决这个问题?我基本上想避免这样做:

foo.BaseValue = aNumber;

所以我可以将对象更像是一个简单的变量,因为代码中有很多地方需要更新许多参数,简化这些赋值语句会很棒。

【问题讨论】:

    标签: c# operators implicit-conversion


    【解决方案1】:

    你想做的事情是不可能的。

    要理解这一点,您需要了解有两种不同类型的强制转换。

    对于值类型(例如double),您正在转换实际值。现在它是具有不同身份的不同事物。因此,编译器不允许保留身份的值类型用户定义强制转换运算符。

    对于引用类型(例如Parameter),您正在转换引用,而不是实际值,因此在技术上可以保留标识(因为对象本身没有改变)。但是,这仅允许通过类型系统提供的强制转换。用户定义的强制转换不保留身份并始终返回一个新对象。

    这让我们看到了你的陈述:

    foo = aNumber;
    

    您正在尝试将值类型分配给引用类型

    正如您间接意识到的那样,没有“实例”,因为您正在从值类型转换为引用类型。您的操作员看起来像这样:

    static public implicit operator Parameter(double p)
    {
        return new Parameter() { BaseValue = p };
    }
    

    如您所见,如果您希望在这些类型之间进行转换,显然您必须创建一个新实例。

    最后,由于您想保留所有其他属性,因此您实际上是在描述一个 setter,您已经拥有它:

    foo.BaseValue = aNumber;
    

    只需输入.BaseValue。你会没事的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-17
      • 2013-01-12
      • 2020-12-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多