【问题标题】:Summing the values of two same-type structs [duplicate]将两个相同类型结构的值相加[重复]
【发布时间】:2020-03-31 20:43:33
【问题描述】:

所以我有一个这样的结构:

public struct Attributes {
    public int vitality;
    public int intelligence;
    public int dexterity;
    public int agility;
}

我是这样使用它的:

Attributes a = new Attributes();
Attributes b = new Attributes();

而我想要实现的是:

Attributes c = new Attributes();
c = a + b;

我希望这给我上面指定的这两个 属性的这 4 个变量的总和。

在结构内部,我尝试了这个:

public static Attributes operator +(Attributes x, Attributes y) {
        PropertyInfo[] info = typeof(Attributes).GetType().GetProperties();
        for (int i = 0; i < info.Length; i++) {                
            info[i].SetValue(x, (int) info[i].GetValue(x) + (int) info[i].GetValue(y), null);
        }

        return x;
}

这显然不起作用,给我一个错误。

你们能帮我解决这个问题吗?我能做些什么来实现我想要的?谢谢。

【问题讨论】:

    标签: c# struct reflection operator-overloading


    【解决方案1】:

    只需使用以下内容:

    public static Attributes operator +(Attributes x, Attributes y) {
            return new Attributes 
            {
                vitality = x.vitality + y.vitality,
                intelligence = x.intelligence + y.intelligence,
                dexterity = x.dexterity+ y.dexterity,
                agility = x.agility + y.agility
            };
    }
    

    如果您不必这样做,则无需花哨并使用反射。这是一个强大的工具,但不要落入金锤谬论。仅在真正需要时使用它。

    编辑:如果你真的想使用反射,这是你的代码的工作版本:

    public static Attributes operator +(Attributes x, Attributes y)
    {
        FieldInfo[] info = typeof(Attributes).GetFields();
        object boxedResult = new Attributes();
        foreach (FieldInfo fi in info)
        {
            fi.SetValue(boxedResult, (int)fi.GetValue(x) + (int)fi.GetValue(y));
        }
    
        return (Attributes)boxedResult;
    }
    

    我认为有必要对我所做的更改进行一些解释:

    1. 如果operator+ 修改了它的一个操作数,我会认为这很不寻常,所以我让它返回一个新的Attributes 结构。
    2. 你打电话给typeof(Attributes).GetType(),它基本上取了Attributes的类型,得到了类型的类型,这绝对不是你想要的。
    3. 您正在检查属性信息,但 Attributes 没有属性,只有字段。
    4. 在设置其字段之前,我明确地将Attributes 结构装箱。对结构进行装箱会生成它的副本,当您采用值类型(例如任何struct)并将其转换为object 时,就会发生装箱。发生的情况是您的值类型(存在于堆栈中)被放入一个整洁的小引用类型框并存储在堆中,因为只有引用类型可以存在于堆中。实际上,它的副本存储在堆上。因此,由于SetValueobject 参数作为“目标”,因此每次都会对结构进行装箱,从而有效地接受您的更改并将它们应用于然后立即丢弃的副本。通过显式装箱,我对结构的同一个副本进行了所有更改,然后在取消装箱后返回。如果 Attributes 是引用类型,则无需执行此步骤。

    【讨论】:

    • 是的,那绝对可行。但是,我有比这更多的变量(它们都是整数),将来可能会添加更多。所以我真的很想保持它的方式。
    • 使用反射来节省自己为类编写运算符的工作似乎是个坏主意。在你的位置,我要么坚持输入你的属性并按照我建议的方式编写运算符,要么将你的属性变成Dictionary&lt;string, int&gt; 之类的东西,然后用 LINQ 求和。
    • 好的,谢谢。另一方面,我真的很想学习一些关于反射的东西,因为我对 C# 很陌生。所以,有机会,你能帮我修复我的代码吗?我想你已经明白了。
    • 我编辑了我的答案以包括工作代码和解释为什么它被破坏。您可能需要一段时间才能将头绕在第 nr 点上。 4,但只是通过它几次并在互联网上阅读。我认为这是一个很好的思考练习,可以帮助您了解物体的真正含义以及它们所在的位置。
    • 天哪。我不知道该怎么感谢你,看看那个漂亮的代码和解释。非常感谢。是的,我对 C# 很陌生,我什至不知道属性和字段之间的区别。所以我的坏。甚至没有说获取类型的类型......我把它变成了一个结构,那是因为我被告知你可以在那些而不是类上为自己设置一个新的运算符。我错了吗?这有点棘手,因为它不是引用类型,我需要几天时间才能完成这样的事情。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多