Why do I get an error about conversion when dealing with generics?

Hi,

So I thought I would write this class which would allow me to easily push values for serialization for different types of structs, so this was the basic idea:

using UnityEngine;
using System.Collections;

public class PlayerSerializable<T> : MonoBehaviour where T : struct {
	
	public T val = default(T);
	
    private void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info) {
        if (stream.isWriting) {
            T refVal = this.val;
            stream.Serialize(ref refVal);
        } else {
            T refVal = default(T);
            stream.Serialize(ref refVal);
            this.val = val;
        }
    }

}

T is past as class generic, has to be struct and a property is stored with type T. Then I thought on the serialize network view function I’d just call Serialize(ref refVal) where refVal would be T (in practical example, a bool, int, NetworkPlayer, etc.). But then I noticed I get this compiler error:

Assets/PlayerSerializable.cs(11,20): error CS1503: Argument `#1' cannot convert `T' expression to type `bool'

But why does it even bother to convert the expression? Why isn’t this checked at runtime? Does anybody have an idea how I would get around this?

Thanks in advance.

If you don’t use it too often, then alternatively you can use reflection, and get much cleaner code:

object[] args = new object[] { this.val };
var typeAssembly = System.Reflection.Assembly.GetAssembly(typeof(T));
var refParamType = typeAssembly.GetType(String.Concat(typeof(T).FullName, "&"));
var serializeMethodInfo = typeof(BitStream).GetMethod("Serialize", new [] { refParamType });
serializeMethodInfo.Invoke(stream, args);

The above code should work for overloads with single ref parameter. That’s why & character is added to the end of type name.

Note that if you wish to use similar code to call method modifying the parameter, then you can access the modified value using args[0] after invoking.

If the struct is not a Serializable, it’s impossible to serialize it automatically without using reflection and implementing your own serialization method. This generic class won’t help it. BitStream class doesn’t support your custom class.

Btw, possible additional typo : Line 15 should be this.val = refval; instead of this.val = val;

lol :slight_smile: started not too long ago, I really like the language. Strict yet versatile. But I guess in the end it makes sense that it throws and error, since the methods are strictly defined. Too bad, if this would have worked it would make generics so much more useful, or at least defined a group of classes/structs as generics or something like that. But now I got to either define a class for each type, or check types, which I already got running, but it would have just been much “prettier” to do it this way.

using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;

[Serializable()]
[RequireComponent(typeof(NetworkView))]
public class PlayerSerializer : MonoBehaviour {

    public Dictionary<JSettings.Serializables, object> values = new Dictionary<JSettings.Serializables, object>();

    public void Register<T>(JSettings.Serializables serializableName, T serializableValue) {
        this.values[serializableName] = serializableValue;
    }

    public void Register<T>(JSettings.Serializables serializableName) {
        this.values[serializableName] = default(T);
    }

    public void Unregister(JSettings.Serializables serializableName) {
        this.values.Remove(serializableName);
    }

    private void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info) {
        if (stream.isWriting) {
            foreach (KeyValuePair<JSettings.Serializables, object> serializable in this.values) {
                if (serializable.Value is int) {
                    int serializeMe = (int) serializable.Value;
                    stream.Serialize(ref serializeMe);
                }
                else if (serializable.Value is float) {
                    float serializeMe = (float) serializable.Value;
                    stream.Serialize(ref serializeMe);
                }
                else if (serializable.Value is char) {
                    char serializeMe = (char) serializable.Value;
                    stream.Serialize(ref serializeMe);
                }
                else if (serializable.Value is bool) {
                    bool serializeMe = (bool) serializable.Value;
                    stream.Serialize(ref serializeMe);
                }
                else if (serializable.Value is Quaternion) {
                    Quaternion serializeMe = (Quaternion) serializable.Value;
                    stream.Serialize(ref serializeMe);
                }
                else if (serializable.Value is Vector3) {
                    Vector3 serializeMe = (Vector3) serializable.Value;
                    stream.Serialize(ref serializeMe);
                }
                else if (serializable.Value is NetworkPlayer) {
                    NetworkPlayer serializeMe = (NetworkPlayer) serializable.Value;
                    stream.Serialize(ref serializeMe);
                }
                else if (serializable.Value is NetworkViewID) {
                    NetworkViewID serializeMe = (NetworkViewID) serializable.Value;
                    stream.Serialize(ref serializeMe);
                }
                else throw new ArgumentException("Unsupported type");
            }

        }
        else...

As I said not so pretty, but an alternative :slight_smile: