views:

88

answers:

3

I want to create a generic method that is only applicable to classes that have the Serializable attribute, e.g.

public static int Foo<T>(T obj) where T : Serializable {
  ...
}

but obviously the above doesn't compile. And I'm guessing if I put SerializableAttribute there, it'll insist that T is an attribute, not a class with that attribute.

How do you do something like this?

+2  A: 

Hi there.

Constraints on attributes cannot be done. One solution could be to use reflection to analyse the object being passed to your method and see if it has the Serializable attribute declared.

Cheers. Jas.

Jason Evans
The base class suggestion isn't really useful, since it's imperative that the leaf class declare that attribute as well. (After all, class `Object` itself is decorated with `[Serializable]`.)
Kirk Woll
@Kirk - Cheers for that, didn't know. Will amend my answer.
Jason Evans
A: 

You must make that classes implement an interface applies that attribute. You may then filter by the interface:

public static int Foo<T>(T obj) where T : ISerializable
{}
gjsduarte
+2  A: 

You could implement the ISerializable interface and use that "where T : ISerializable" but then you have to implement the ISerializable methods in every class. A run-time check can look for the SerializableAttribute on the class, but then you don't have compile time checks. You could consider writing your own interface that has very little to have to implement, maybe just a Property and implement that interface on each of your classes. Something like...

public interface ISerializableSet {
    bool IsSerializable { get; }
}

Your implementation could use reflection then to do a run-time check, your Foo method would be declared "where T : ISerializableSet" for your compile time check.

Here is a more complete example...

public interface ISerializableSet
{
    bool IsSerializable { get; }
}

[Serializable]
class SerializableClass : ISerializableSet
{
    [NonSerialized]
    private bool _runTimeCheck = true;

    #region ISerializableSet Members
    public bool IsSerializable
    {
        get { 
            if(!_runTimeCheck)
                return true;
            if(0 != (this.GetType().Attributes & System.Reflection.TypeAttributes.Serializable))
                return true;
            return false;
        }
    }
    #endregion
}

public static class Bar2
{
    public static int Foo<T>(T obj) where T : ISerializableSet
    {
        ISerializableSet sc = obj;
        Console.WriteLine("{0}", sc.IsSerializable.ToString());
        return 1;
    }
}

You could test the IsSerializable property in your constructor and throw a run-time exception in case someone removes [Serializable] inadvertantly. If you are using Unit Tests, you can detect problems at test time.

Les