C# 编写一个泛型方法,在泛型参数上有两组可能的约束

C# 编写一个泛型方法,在泛型参数上有两组可能的约束,c#,generics,generic-programming,C#,Generics,Generic Programming,我正在寻求编写一个TypedBinaryReader,它能够读取BinaryReader通常支持的任何类型,以及实现特定接口的类型。我已经非常接近了,但我还没有完全达到 对于值类型,我将这些类型映射到调用适当函数的functor 对于引用类型,只要它们继承了我指定的接口并且可以构造,下面的函数就可以工作 但是,我想创建一个通用的泛型方法调用,ReadUniversal(),它既适用于值类型,也适用于上述指定的引用类型 这是第一次尝试,它很有效,但它不是通用的,我仍然需要一些案例 public c

我正在寻求编写一个
TypedBinaryReader
,它能够读取BinaryReader通常支持的任何类型,以及实现特定接口的类型。我已经非常接近了,但我还没有完全达到

对于值类型,我将这些类型映射到调用适当函数的functor

对于引用类型,只要它们继承了我指定的接口并且可以构造,下面的函数就可以工作

但是,我想创建一个通用的泛型方法调用,
ReadUniversal()
,它既适用于值类型,也适用于上述指定的引用类型

这是第一次尝试,它很有效,但它不是通用的,我仍然需要一些案例

public class TypedBinaryReader : BinaryReader {

        private readonly Dictionary<Type, object> functorBindings;

        public TypedBinaryReader(Stream input) : this(input, Encoding.UTF8, false) { }

        public TypedBinaryReader(Stream input, Encoding encoding) : this(input, encoding, false) { }

        public TypedBinaryReader(Stream input, Encoding encoding, bool leaveOpen) : base(input, encoding, leaveOpen) {
            functorBindings = new Dictionary<Type, object>() {
                {typeof(byte), new Func<byte>(ReadByte)},
                {typeof(int), new Func<int>(ReadInt32)},
                {typeof(short), new Func<short>(ReadInt16)},
                {typeof(long), new Func<long>(ReadInt64)},
                {typeof(sbyte), new Func<sbyte>(ReadSByte)},
                {typeof(uint), new Func<uint>(ReadUInt32)},
                {typeof(ushort), new Func<ushort>(ReadUInt16)},
                {typeof(ulong), new Func<ulong>(ReadUInt64)},
                {typeof(bool), new Func<bool>(ReadBoolean)},
                {typeof(float), new Func<float>(ReadSingle)}
            };
        }


        public T ReadValueType<T>() {
            return ((Func<T>)functorBindings[typeof(T)])();
        }

        public T ReadReferenceType<T>() where T : MyReadableInterface, new() {
            T item = new T();
            item.Read(this);
            return item;
        }

        public List<T> ReadMultipleValuesList<T, R>() {
            dynamic size = ReadValueType<R>();
            List<T> list = new List<T>(size);
            for (dynamic i = 0; i < size; ++i) {
                list.Add(ReadValueType<T>());
            }

            return list;
        }

        public List<T> ReadMultipleObjecsList<T, R>() where T : MyReadableInterface {
            dynamic size = ReadValueType<R>();
            List<T> list = new List<T>(size);
            for (dynamic i = 0; i < size; ++i) {
                list.Add(ReadReferenceType<T>());
            }

            return list;
        }
}
但是,由于对泛型参数T的不同约束,这将不起作用。有什么办法让它工作吗


最终目标是只使用一个方法来读取BinaryReader通常可以读取的任何类型或实现接口的任何类型。

如果您需要一个方法来处理引用类型和一个方法来处理值类型,这是拥有两个方法的完全合理的理由

从调用此类中的方法的代码的角度来看,这可能会有所帮助。从他们的角度来看,如果他们可以不考虑类型而只调用一个方法,而不必为值类型调用一个方法,为值类型调用另一个方法,他们会受益吗?可能不会

发生的事情(我已经做了很多次)是,我们被我们想要某个类的外观或行为所困扰,原因与我们试图编写的实际软件无关。根据我的经验,当我们试图编写泛型类时,这种情况经常发生。泛型类在我们处理的类型无关紧要的情况下(例如,如果我们有一个类用于int列表,另一个类用于double列表,等等),当我们看到不必要的代码重复时,泛型类会帮助我们

然后,当我们开始实际使用我们创建的类时,我们可能会发现我们的需求与我们所想的不完全一样,我们花在修饰泛型类上的时间也浪费了

如果我们正在处理的类型确实需要完全不同的代码,那么将多个不相关类型的处理强制到单个泛型方法中会使代码更加复杂。(每当我们感到被迫使用
动态
时,这是一个很好的迹象,表明某些东西可能变得过于复杂了。)


我的建议是只编写所需的代码,如果需要调用不同的方法,不要担心。看看它是否真的造成了问题。可能不会。在问题出现之前不要试图解决它。

如果您需要一个方法来处理引用类型和一个方法来处理值类型,那么这就是拥有两个方法的一个非常有效的理由

从调用此类中的方法的代码的角度来看,这可能会有所帮助。从他们的角度来看,如果他们可以不考虑类型而只调用一个方法,而不必为值类型调用一个方法,为值类型调用另一个方法,他们会受益吗?可能不会

发生的事情(我已经做了很多次)是,我们被我们想要某个类的外观或行为所困扰,原因与我们试图编写的实际软件无关。根据我的经验,当我们试图编写泛型类时,这种情况经常发生。泛型类在我们处理的类型无关紧要的情况下(例如,如果我们有一个类用于int列表,另一个类用于double列表,等等),当我们看到不必要的代码重复时,泛型类会帮助我们

然后,当我们开始实际使用我们创建的类时,我们可能会发现我们的需求与我们所想的不完全一样,我们花在修饰泛型类上的时间也浪费了

如果我们正在处理的类型确实需要完全不同的代码,那么将多个不相关类型的处理强制到单个泛型方法中会使代码更加复杂。(每当我们感到被迫使用
动态
时,这是一个很好的迹象,表明某些东西可能变得过于复杂了。)

我的建议是只编写所需的代码,如果需要调用不同的方法,不要担心。看看它是否真的造成了问题。可能不会。在问题出现之前不要试图解决它

 public class Value<T> : MyReadableInterface {

        private T value;

        public Value(T value) {
            this.value = value;
        }

        internal Value(TypedBinaryReader reader) {
            Read(reader);
        }

        public T Get() {
            return value;
        }

        public void Set(T value) {
            if (!this.value.Equals(value)) {
                this.value = value;
            }
        }

        public override string ToString() {
            return value.ToString();
        }

        public void Read(TypedBinaryReader reader) {
            value = reader.ReadValueType<T>();
        }
    }
public T ReadUniversal<T>() {
    if ((T).IsSubclassOf(typeof(MyReadableInterface)) {
        return ReadReferenceType<T>();
    } else if (functorBindings.ContainsKey(typeof(T)) {
        return ReadValueType<T>();
    } else {
        throw new SomeException();
    }
}