gpt4 book ai didi

c# - 实现处理不同整数类型集合的泛型方法的正确方法是什么?

转载 作者:行者123 更新时间:2023-11-30 12:47:16 24 4
gpt4 key购买 nike

我正在编写一种特殊的 System.IO.BinaryWriter。作者应该能够处理整数类型,包括 Enum,以及这些类型的集合

abstract class MyBinaryWriter
{
// ...

#region Methods: Basic Types: Writing
public abstract void Write(byte value);
public abstract void Write(ushort value);
public abstract void Write(uint value);
public abstract void Write(ulong value);
public abstract void Write(string value);
#endregion

#region Methods: Complex Types: Writing
public virtual void Write<T>(ICollection<T> collection)
{
// first write the 32-bit-unsigned-length prefix
if (collection == null || collection.Count == 0)
{
Write((uint)0);
}
else
{
Write((uint)collection.Count);

// then write the elements, if any
foreach (var item in collection)
; // What here? Obviously Write(item) doesn't work...
}
}

// ...
}

处理此问题的最佳方法是什么?有比为每个整数类型和我希望处理的每个枚举类型编写重载更好的解决方案吗?一个可能的解决方案如下,但我不太喜欢,并且有潜在的性能问题。

    #region Methods: Complex Types: Writing
public virtual void Write<T>(ICollection<T> collection) where T : IConvertible
{
// first write the 32-bit-unsigned-length prefix
if (collection == null || collection.Count == 0)
{
Write((uint)0);
}
else
{
Write((uint)collection.Count);

// get the method for writing an element
Action<T> write = null;
var type = typeof(T);
if (type.IsEnum)
type = Enum.GetUnderlyingType(type);

switch (Type.GetTypeCode(type))
{
case TypeCode.Byte:
case TypeCode.SByte:
write = (x => Write((byte)(IConvertible)x.ToByte(null)));
break;

case TypeCode.Int16:
case TypeCode.UInt16:
write = (x => Write((ushort)(IConvertible)x.ToUInt16(null)));
break;

case TypeCode.Int32:
case TypeCode.UInt32:
write = (x => Write((uint)(IConvertible)x.ToUInt32(null)));
break;

case TypeCode.Int64:
case TypeCode.UInt64:
write = (x => Write((ulong)(IConvertible)x.ToUInt64(null)));
break;

default:
Debug.Fail("Only supported for integral types.");
break;
}

// then write the elements, if any
foreach (var item in collection)
write(item);
}
}

最佳答案

一种方法是使用编译表达式:

// helper classes which compiles a fast, type-safe delegate for writing various types
static class MyBinaryWriterHelper<T> {
public static readonly Action<MyBinaryWriter, T> WriteAction;

// this initialization is a bit expensive, but it will occur only once
// for each writable type T and will occur lazily
static {
// find the existing Write(T) on the MyBinaryWriter type
var writeMethod = typeof(MyBinaryWriter).GetMethods()
.FirstOrDefault(m => m.Name == "Write"
&& m.GetArguments().Length == 1
&& m.GetArguments()[0](p => p.ParameterType == typeof(T)
);

// if there is no such method, fail
if (writeMethod == null) { throw ... }

// build up an expression (writer, t) => writer.Write(t)
var writerParam = Expression.Parameter(typeof(MyBinaryWriter));
var tParam = Expression.Parameter(typeof(T));
var call = Expression.Call(writerParam, writeMethod, tParam);
var lambda = Expression.Lambda<Action<MyBinaryWriter, T>>(call, new[] { writerParam, tParam });

// compile the expression to a delegate, caching the result statically in the
// readonly WriteAction field
WriteAction = lambda.Compile();
}
}

// then in your writer class
public void Write<T>(IEnumerable<T> collection) {
// other collection writing logic (e. g. writing the count) ...

// to write out the items, just use the static action field
foreach (var t in collection) {
MyBinaryWriterHelper<T>.WriteAction(this, t);
}
}

虽然无法使用泛型来强制类型为“数字”,但您可以使用 IConvertible(如您的示例代码中)作为松散约束,以增加额外的编译时安全性。

关于c# - 实现处理不同整数类型集合的泛型方法的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17392540/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com