C# 属性,是否可以绕过定义get而不定义set(无支持变量)?

C# 属性,是否可以绕过定义get而不定义set(无支持变量)?,c#,properties,C#,Properties,假设您有一个具有300个属性且没有支持变量的类,每个属性都返回一个十进制/双精度 例如: public decimal MathValue { get; set; } 现在您决定这些值中的每一个都应该四舍五入 我正在寻找最简单的方法来重构它,而不必重写所有这些属性 public class Base { public virtual decimal MathValue { get; set; } } public class Derived : Base { public o

假设您有一个具有300个属性且没有支持变量的类,每个属性都返回一个十进制/双精度

例如:

public decimal MathValue { get; set; }
现在您决定这些值中的每一个都应该四舍五入

我正在寻找最简单的方法来重构它,而不必重写所有这些属性

public class Base
{
    public virtual decimal MathValue { get; set; }
}

public class Derived : Base
{
    public override decimal MathValue
    {
        get { return Math.Round(base.MathValue); }
    }
}
这个等价物中实际起作用的东西:D:

public decimal MathValue { get {return Math.Round(MathValue);} set; }

否。如果在getter或setter中需要任何自定义逻辑,则不能使用自动属性。

您可以创建一个新的值类型,该类型假装为十进制,但返回舍入值。大概是这样的:

struct RoundedDecimal
{
    public decimal Value { get; private set; }

    public RoundedDecimal(decimal value) : this()
    {
        this.Value = value;
    }

    public static implicit operator decimal(RoundedDecimal d)
    {
        return Math.Round(d.Value);
    }
}
public class Base
{
    public virtual decimal MathValue { get; set; }
}

public class Derived : Base
{
    public override decimal MathValue
    {
        get { return Math.Round(base.MathValue); }
    }
}

类中的每个属性都应该是
RoundedDecimal
类型,而不是
decimal

,但是如果客户端不需要舍入值,会发生什么呢?也就是说,一些新的客户端代码设置了一个十进制数,并期望返回“精确”值


如果一些客户机确实需要对属性调用的输出进行取整,那么客户机应该处理这个问题,让您的类自己处理

您可以创建此类的派生,该派生重写get并返回舍入值。然后需要将基本属性修改为虚拟属性。但这将允许您在不定义集合和使用自动属性的情况下定义get

public class Base
{
    public virtual decimal MathValue { get; set; }
}

public class Derived : Base
{
    public override decimal MathValue
    {
        get { return Math.Round(base.MathValue); }
    }
}

Visual Studio以前有一个内置的“prop”代码段,它将生成类似以下代码的内容:

    private decimal _MathValue;

    public decimal MathValue
    {
        get { return _MathValue; }
        set { _MathValue = value; }
    }
这将为您提供最完整的解决方案,但自VS 2008以来,它现在会生成自动属性版本:

    public decimal MathValue { get; set; }

我还没有尝试过,但是:

一个选项是使用面向方面的编程在返回时拦截属性调用,并在将控制权传递回调用方之前对返回值进行取整。

重构代码的最简单方法是什么?下面是我要做的:

  • 打开记事本++(如果没有,请获取)
  • 将类的所有属性复制/粘贴到空白文本区域
  • 将光标放置在第一行的开头: 公共十进制MathValue1{get;set;}
  • 开始录制宏(单击工具栏上的录制按钮)
  • 按住ctrl+向右箭头键(称为“word right”)3次,将光标放在属性名称的开头
  • 执行shift+ctrl+right arrow组合键1次,然后进行复制以将属性名称放入剪贴板
  • word right再重复3次,将光标放在“get”之后
  • 删除get之后的分号,并开始键入“{return Math.Round(389;)”
  • 做一个浆糊 10类型“;}”
  • word right再重复2次,将光标放在“set”之后
  • 删除集合后的分号,然后开始键入“{uu1”
  • 做一个浆糊
  • 类型“=值;}
  • 按结束键将光标移到行尾
  • 按向右箭头键将光标移到下一行的开头
  • 按停止按钮结束宏(工具栏上的方形按钮)
  • 单击“多次运行宏”按钮(工具栏上的双箭头图标)并说“运行到文件结束”
  • 将生成的文本复制/粘贴回类中,以替换原始特性定义
  • 现在,您需要定义一组相应的私有变量,这些变量以下划线开头,但在其他方面与属性具有相同的名称。从类中的属性的新副本开始,并执行一组类似的步骤,如上所述

    我的假设是每行以2个选项卡开始,属性之间没有空行

    public class Base
    {
        public virtual decimal MathValue { get; set; }
    }
    
    public class Derived : Base
    {
        public override decimal MathValue
        {
            get { return Math.Round(base.MathValue); }
        }
    }
    

    而不是让每个属性调用Mault.St圆,您可能需要考虑定义自己的实用函数,它们都调用,这样,如果您需要再次更改它,就可以在一个地方更改它。

    < P>您可以使用其他基于.NET的AOP框架来实现这一点。"

    这可以做到:

    [Serializable]
    public class RoundingAttribute : OnMethodBoundaryAspect
    {
        public override void OnExit(MethodExecutionEventArgs eventArgs)
        {
            base.OnExit(eventArgs);
            eventArgs.ReturnValue = Math.Round((double)eventArgs.ReturnValue, 2);
        }
    }
    
    class MyClass
    {
        public double NotRounded { get; set; }
    
        public double Rounded { [Rounding] get; set; }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            var c = new MyClass
                    {
                        Rounded = 1.99999, 
                        NotRounded = 1.99999
                    };
    
            Console.WriteLine("Rounded = {0}", c.Rounded); // Writes 2
            Console.WriteLine("Not Rounded = {0}", c.NotRounded);  // Writes 1.99999
        }
    }
    

    如果不为每个变量声明一个变量,绝对没有办法覆盖这个逻辑或解决方案?另一种方法是编写一个命令行util(或者最好使用T4)从其他文件/数据为您生成300个属性。您可以使用类似PostSharp的方法在编译后重写属性。然而,对于这样琐碎的事情,可能不值得这么做。我认为这更多的是一个理论问题,而不是一个暴力问题。。。我愿意接受任何能帮助我用最少代码解决问题的想法。我不知道这是如何回答他的问题的。我称之为
    Int96
    ,因为它实际上就是这样。这是一种在不破坏接口的情况下实现它的好方法。实际上,如果您创建一个名为Value的公共只读字段,并在构造函数中对其进行四舍五入,可能会更好。到目前为止,我最喜欢这个解决方案。:)这也很容易实现。ctrl-h“decimal”“RoundedDecimal”那么在这种情况下,get就可以单独处理:)对于那个特定的属性。。。我唯一想做的就是避免为每个属性声明一个变量。这是如何实现的?如果可能的话,我想覆盖GET本身。你能给我举个例子吗?当然。我还澄清了整个属性需要是虚拟的,而不仅仅是getter。继承在这方面似乎有些过火。对于“是否有可能绕过定义get而不定义set”的问题,我不同意。从更广泛的角度来看,这种方法也为他提供了一个全面和不全面的课程版本。由此产生的类名可以具有更好的语义。然而,我同意,除非他能获得这些特殊的好处,否则这可能是过火了。我更感兴趣的是围绕代码的方式,而不是手动重构类中的所有内容,即使我有一个代码片段可以为我实现。啊,y