给出下面的扩展方法:
public static class Ext
{
public static void Serialize(this Guid guid_, StringWriter sw_)
{
sw_.Write(guid_.ToString("B"));
}
}
和班级:
public class Field<T>
{
public T value;
public void Serialize(StringWriter sw_)
{
value.Serialize(sw_);
}
}
我想做以下事情,但无法弄清楚:
public class Foo
{
public Field<Guid> uid;
public Foo()
{
// assume StringWriter object sw;
uid.Serialize(sw);
}
}
显然现实情况更复杂,这只是一个简单的例子。
修改
编译器错误:
错误CS1928:'T'不包含'Serialize'的定义,并且最好的扩展方法重载'Ext.Serialize(System.Guid,StringWriter)'有一些无效的参数
错误CS1929:实例参数:无法从'T'转换为'System.Guid'
答案 0 :(得分:1)
这是不可能的,因为在编译时肯定不知道T
是否为Guid
。
但你可以做这样的事情
public class GuidField : Field<Guid>
{
public override void Serialize(StringWriter sw_)//Assume we have made base class method virtual
{
value.Serialize(sw_);
}
}
这是有效的,因为c#编译器在编译时知道value
是Guid
。
public void Serialize(StringWriter sw_)
{
if (typeof (T) == typeof (Guid))
{
((Guid)(object)value).Serialize(sw_);
}
}
答案 1 :(得分:1)
无法应用限制,以使“T
仅为具有为”。“定义的扩展方法的类型。
如果你真的需要为此使用泛型,你必须为每个可以序列化的类型创建一个适配器,如下:
public static class Ext
{
public static void Serialize(this Guid guid_, StringWriter sw_)
{
sw_.Write(guid_.ToString("B"));
}
}
public class Field<T> where T: ISerializableField
{
public T value;
public void Serialize(StringWriter sw_)
{
value.Serialize(sw_);
}
}
public interface ISerializableField
{
void Serialize(StringWriter sw);
}
public class SerializableGuid : ISerializableField
{
private readonly Guid _guid;
public SerializableGuid(Guid guid)
{
_guid = guid;
}
public void Serialize(StringWriter sw)
{
_guid.Serialize(sw);
}
}
此适配器包装给定类型的实例,并公开一种序列化它的方法。
请注意,T
中的Field<T>
现在仅适用于适配器ISerializableField
的实例 - 现在Field<T>
确定T
的所有实例都可以< / em>被序列化。
就此而言,您不再需要扩展方法,适配器可以自行执行序列化。除非您的代码的其他部分也想要序列化guid。
修改强>
如果避免为每个可序列化的类型创建一个类是您的首要任务,并且您不介意丢失类型安全性,则可以使用动态调用:
public class Field
{
private dynamic Value { get; set; }
public void Serialize(StringWriter sw)
{
try
{
Value.Serialize(sw);
}
catch (RuntimeBinderException ex)
{
throw new InvalidOperationException(string.Format("Instance of type {0} does not implement a Serialize method", Value.GetType()), ex);
}
}
}
不再需要仿制药了。仿制药强制执行类型安全,我们就把它扔掉了。
答案 2 :(得分:1)
我猜你会为每种类型编写一堆扩展(Serializers)方法。这是可能的,但有一些反思魔法。
public static class Ext
{
public static void Serialize(this Guid guid_, StringWriter sw_)
{
sw_.Write(guid_.ToString("B"));
}
public static void Serialize(this int id, StringWriter sw_)
{
sw_.Write(id.ToString());
}
}
public class Field<T>
{
public T value;
private static Lazy<Action<T, StringWriter>> _serializer = new Lazy<Action<T, StringWriter>>(() => (Action<T, StringWriter>)Delegate.CreateDelegate(typeof(Action<T, StringWriter>), typeof(Ext), "Serialize"), true);
public void Serialize(StringWriter sw_)
{
_serializer.Value(value, sw_);
}
}
答案 3 :(得分:0)
Field类中的问题是,T是泛型类型,此时它是“未知”,因此扩展方法不会显示,因为扩展方法是GUID的具体类型。 您可能需要检查T是否为guid,如果是,则执行转换为GUID,然后允许您调用扩展方法 - 所以不确定它是否会编译。
关于你在Foo类中的最后一个例子 - 是不是GUID?如果是这样,你导入Ext类存在的项目和命名空间?如果不是 - 那么它应该会出现。