繁体   English   中英

使用两个泛型类型参数推断泛型类型 [重复]

[英]Infer generic type with two generic type parameters [duplicate]

我有以下方法

public bool HasTypeAttribute<TAttribute, TType>(TType obj)
{
    return typeof(TType).GetCustomAttribute<TAttribute>() != null;
}

我希望能够像这样使用它:

MyClass instance = new MyClass();

TypeHelper.HasTypeAttribute<SerializableAttribute>(instance);

但我无法让它工作,因为

类型参数的数量不正确

所以我需要打电话

TypeHelper.HasTypeAttribute<SerializableAttribute, MyClass>(instance);

这当然有道理,但为什么编译器不能推断传递对象的类型? 因为如果方法看起来像这样:

public void Demo<T>(T obj)
{
}

编译器肯定能够推断出类型,这样我就可以写

Foo.Demo(new Bar());

代替

Foo.Demo<Bar>(new Bar());

那么,有没有办法在这种情况下进行类型推断? 这是我的设计缺陷还是我可以实现我想要的? 重新排序参数也无济于事...

因为 C# 规则不允许这样做。

C# 有一个规则是可行的,如果某些类型与参数相关(因此至少在某些时候可以推断出)并且显式给定类型的数量与剩余不可推断的数量相同类型,那么两者将协同工作。

这需要有人提出建议,说服其他参与 C# 决策的人这是一个好主意,然后才能实施。 这还没有发生。

除了特性开始必须证明自己值得它们带来的额外复杂性这一事实之外(向语言添加任何东西,它会立即变得更加复杂,更多的工作,更多的编译器错误的机会等),那么问题是,它是一个好主意?

另外,您在这个特定示例中的代码会更好。

不利的一面是,现在每个人的代码都稍微复杂了一些,因为错误的方式可能会更多,从而导致代码在运行时失败而不是编译时失败,或者导致错误消息不太有用。

人们已经发现一些关于推理的案例令人困惑,这表明添加另一个复杂案例无济于事。

这并不是说这绝对是一个坏主意,只是有优点和缺点使它成为一个意见问题,而不是明显的缺乏。

可以将调用分解为多个步骤,这样可以在任何可能的地方进行类型推断。

public class TypeHelperFor<TType>
{
    public bool HasTypeAttribute<TAttribute>() where TAttribute : Attribute
    {
        return typeof(TType).GetCustomAttribute<TAttribute>() != null;
    }
}

public static class TypeHelper
{
    public static TypeHelperFor<T> For<T>(this T obj)
    {
        return new TypeHelperFor<T>();
    }
}

// The ideal, but unsupported
TypeHelper.HasTypeAttribute<SerializableAttribute>(instance);
// Chained
TypeHelper.For(instance).HasTypeAttribute<SerializableAttribute>();
// Straight-forward/non-chained
TypeHelper.HasTypeAttribute<SerializableAttribute, MyClass>(instance);

对于这种情况,这应该可以正常工作,但是我警告不要在最终方法返回 void 的情况下使用它,因为如果您不对返回值执行任何操作,很容易使链保持半成形。

例如

// If I forget to complete the chain here...
if (TypeHelper.For(instance)) // Compiler error

// But if I forget the last call on a chain focused on side-effects, like this one:
// DbHelper.For(table).Execute<MyDbOperationType>();
DbHelper.For(table); // Blissfully compiles but does nothing

// Whereas the non-chained version would protect me
DbHelper.Execute<MyTableType, MyDbOperationType>(table);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM