Is it possible to use generic constraints based on attributes rather than types? [duplicate]

心不动则不痛 提交于 2019-12-23 15:35:38

问题


I'm trying to write a class that will be in charge of persisting application options. Since the options need to be persisted the values that I'm sent must be serialisable.

Initially I thought I've be able to write a method with a signature like this:

Public Sub SaveOption(Of T As ISerializable)(ByVal id As String, ByVal value As T)

or if you prefer C#:

public void SaveOption<T>(string id, T value) where T : ISerializable  

In principle this would be fine, but what about types that have the <Serializable> attribute? The most notable example of this is System.String, it does not implement ISerializable, but clearly it is a type that I should be able to save.

So, is there a way that I can restrict which types are allowed into a method at compiletime, based on their attributes?


回答1:


You could have overloads for the other types - taking your string example:

public void SaveOption(string id, string value)

However; serializability is... tricky; I expect you're going to have to check this at runtime.




回答2:


An attribute constraint wouldn't achieve much, since an attribute doesn't generally offer any guarantees at compile time, they're information for the runtime rather than the compiler.

In the serialization case, the [Serializable] attribute is only an indicator that you can attempt serialization at runtime, while ISerializable guarantees that you can serialize it, because you can definitely call GetObjectData and it's the class's problem to ensure that that does the right thing.

For example, I can have

[Serializable]
class GoodClass
{
    public object Property { get; set; }
}

class BadClass
{
}

but GoodClass is really no better than BadClass, because I can do

MemoryStream ms = new MemoryStream();
BinaryFormatter f = new BinaryFormatter();

GoodClass obj = new GoodClass();
f.Serialize(ms, obj); // OK

obj.Property = new BadClass();
f.Serialize(ms, obj); // BOOM

EDIT: Attributes also aren't inherited, so the compiler can't be sure that the object passed at runtime will still have the attribute you demanded:

class NotSoGoodClass : GoodClass // No [Serializable] attribute
{
}

...

SaveOption<GoodClass>( "id", new NotSoGoodClass() ) // oops



回答3:


Nope. :(

Ah, no, actually in C# 4.0 they've introduced code contracts. That should work here.

Example from this link: CLR 4.0: Code Contracts

public void BuyMoreStuff(Item[] cart, ref Decimal totalCost, Item i)
{       
    CodeContract.Requires(totalCost >=0);
    CodeContract.Requires(cart != null);
    CodeContract.Requires(CodeContract.ForAll(cart, s => s != i));

    CodeContract.Ensures(CodeContract.Exists(cart, s => s == i);
    CodeContract.Ensures(totalCost >= CodeContract.OldValue(totalCost));
    CodeContract.EnsuresOnThrow<IOException>(totalCost == CodeContract.OldValue(totalCost));

    // Do some stuff
    …
}



回答4:


It is possible to check for this, but you're right, it will have to be done at runtime, but more formally than just throwing an exception.

public static byte[] SerializeObject<T>(this T obj)
{
    Contract.Requires(typeof(T).IsSerializable);
    ...
}


来源:https://stackoverflow.com/questions/1346485/is-it-possible-to-use-generic-constraints-based-on-attributes-rather-than-types

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!