0

I'm making an attempt to write a class for storing, processing, saving and loading data. I hope that when I finally finish it, it will simplify and mostly automate the process of organizing large numbers of fields, saving them to files and later retrieving them from those files.

My first thought was to use dynamics, but I didn't like the performance drop of even one dynamic, and the class in its original form had many dynamics. I figured I would eliminate all of that and just use generics, which does make things a bit smoother. It also reduces the amount of required code. However, I have run into a new problem. I'm trying to overload operators to make the manipulation of the values a little bit easier.

It's set up like this:

public class DataElement<T>
{

        public T In;
        public T Out;

}

That's an extremely simplified and watered down version, but it is enough for what I'm currently struggling with. Here's the problem:

        public static DataElement<T> operator +(DataElement<T> d, T val)
        {
            object o = val;
            object oo = d.Out;
            if (typeof(T) == typeof(string))
            {
                string s = o.ToString();
                s += oo.ToString();
                oo = s;
            }
            else
            {
                if (typeof(T) == typeof(int))
                {
                    int i = int.Parse(o.ToString());
                    i += int.Parse(oo.ToString());
                    oo = i;
                }
                else if (typeof(T) == typeof(float))
                {
                    float f = float.Parse(o.ToString());
                    f += float.Parse(oo.ToString());
                    oo = f;
                }
                else if (typeof(T) == typeof(long))
                {
                    long l = long.Parse(o.ToString());
                    l += long.Parse(oo.ToString());
                    oo = l;
                }
                else if (typeof(T) == typeof(char))
                {

                }
            }
            d.Out = (T)oo;
            return d;
        }

I'm not even sure if that's going to work. I haven't tested it yet. Mostly because I don't like it. All those IF statements. It's ugly and clunky. The ideal solution would be to use a SWITCH statement, but oh no. VS tells me that SWITCH statements for Types is only supported in the absolute newest versions of C#. And I can't think of any other way to do it. If I try directly, like this:

    d.Out += val;

VS tells me "Operator '+=' cannot be applied to operands of type 'T' and 'T'" Okay, then. How does one accomplish what I'm trying to do? When I had "val" set to "int" instead of generic "T", it told me the same thing. Is there something I'm missing? Am I reinventing the wheel here?

Filburt
  • 17,626
  • 12
  • 64
  • 115
  • 1
    Does https://stackoverflow.com/questions/70651779/use-same-method-to-add-1-to-a-casted-string-that-can-be-either-float-or-int/70651916#70651916 help you? You're looking for a feature that just was not available until very recently. – PMF Jan 18 '22 at 07:48
  • What version of C# are you compiling in? we've been able to switch types using pattern matching since v7. It has improved heaps but _"SWITCH statements for Types is only supported in the absolute newest versions of C#"_ is only in reference to your attempted syntax, not the concept of switching types. – Chris Schaller Jan 18 '22 at 08:03
  • 7.3. I just tried it using "switch(typeof(T))" and it gave me the following error: "Feature 'type pattern' is not available in C# 7.3. Please use language version 9.0 or greater." – SawmillTurtle Jan 18 '22 at 08:11
  • Given the fact that the list of integral types is small, it's probably easier to forgo generics and just write separate overloads – Charlieface Jan 18 '22 at 09:42
  • Given that you are using `typeof` and general _boxing_ logic, there is no real value to using a _generic_ operator at all, why not just use object for the operator? – Chris Schaller Jan 18 '22 at 11:56

2 Answers2

0

If you are stuck with an older version you can cast T to TOther like so:(TOther)(object)o.

if (typeof(T) == typeof(int)) {
    int i = (int)(object)o;
    ...

As for the switch there is an equally ugly solution to switch on the name of the Type. Hopefully someone can improve on this also for older c# versions.

Clemens
  • 588
  • 6
  • 9
0

The real solution to this problem would be to use generic constraints to restrict T to a type that support addition. Unfortunately there no common interface for the integral numeric types, but there are threads with a long list of workarounds.

My suggestion would be to delegate the problem to the caller, i.e.

public DataElement<T> Add(T val, Func<T, T, T> addMethod){
       return new DataElement<T>{In = this.In, Out = addMethod(this.Out, val)};
}

Note that this uses a regular method instead of an operator, since operators has to fulfill some specific rules. I would also be very careful with mutating the input objects, I would usually expect basic methods like 'add' to return a new object, and not to modify the input objects.

However, if the goal is

write a class for storing, processing, saving and loading data

Then I would suggest using a serialization library, at least for the "storing, saving and loading" parts. Since these are purpose made for converting objects to a serialized form that can be saved to disk or sent over the network etc. Json.Net is a popular alternative, but there are many other alternatives.

JonasH
  • 28,608
  • 2
  • 10
  • 23
  • That's a good sugggestion. I've also considered doing something like: `public static DataElement operator +(DataElement d, dynamic val) { dynamic input = d.Out; dynamic output = input + val; d.Out = output; }` Logically, this seems to make sense. If 'Input' and 'Output' are both strings, the value will be appended. If they are numeric, like 'int' or 'float', the addition will work as expected. Is this correct? – SawmillTurtle Jan 18 '22 at 17:49
  • @SawmillTurtle I would not recommend using 'dynamic', since it removes compile time checks and is fairly slow. I would also be careful with mixing addition and concatenation, while they may share operator in c#, they are fundamentally different things. It would be helpful if you could describe your actual problem in more detail, since this sounds a bit like a X/Y problem. – JonasH Jan 19 '22 at 07:46