1

给定以下扩展方法:

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”

4

4 回答 4

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# 编译器知道valueGuid在编译时。


以下方式将起作用,但它会破坏“泛型”的观点。也不推荐。为了说明如何做,我举了一个例子

public void Serialize(StringWriter sw_)
{
    if (typeof (T) == typeof (Guid))
    {
        ((Guid)(object)value).Serialize(sw_);
    }
}
于 2013-11-14T08:34:44.873 回答
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);
    }
}

此适配器包装给定类型的实例并公开一种对其进行序列化的方法。请注意,Tin Field<T>now 仅适用于适配器的实例ISerializableField- 现在Field<T>确定所有实例T 可以序列化。

在那一点上,您不再需要扩展方法,适配器可以自己执行序列化。除非您的代码的其他部分也想要序列化 ​​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);
        }
    }
}

不再需要泛型。泛型强制执行类型安全,我们将其丢弃。

于 2013-11-14T08:37:27.650 回答
1

我猜你将为每种类型编写一堆扩展(序列化器)方法。这是可能的,但有一些反射魔法。

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_);
    }

}
于 2013-11-14T09:09:17.917 回答
0

您的 Field 类中的问题是,T 是泛型类型,此时它是“未知的”,因此不会显示扩展方法,因为扩展方法是 GUID 的具体类型。您可能需要检查 T 是否属于 guid,如果是,请转换为 GUID,这将允许您调用扩展方法 - 所以不确定它是否会编译。

至于您在 Foo 类中的最后一个示例 - uid 是 GUID 吗?如果是这样,您是否导入了 Ext 类所在的项目和命名空间?如果不是 - 你应该然后它会出现。

于 2013-11-14T08:29:18.640 回答