Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用两个泛型类型参数推断泛型类型_C#_Generics_Type Inference - Fatal编程技术网

C# 使用两个泛型类型参数推断泛型类型

C# 使用两个泛型类型参数推断泛型类型,c#,generics,type-inference,C#,Generics,Type Inference,我有以下方法 public bool HasTypeAttribute<TAttribute, TType>(TType obj) { return typeof(TType).GetCustomAttribute<TAttribute>() != null; } 而不是 Foo.Demo<Bar>(new Bar()); Foo.Demo(新条()); 那么,在这种情况下,有没有一种方法可以使类型推断工作?这是我的设计缺陷还是我能实现我想要的?

我有以下方法

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

Foo.Demo<Bar>(new Bar());
Foo.Demo(新条());
那么,在这种情况下,有没有一种方法可以使类型推断工作?这是我的设计缺陷还是我能实现我想要的?对参数重新排序也没有帮助…

因为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);
公共类类型帮助器
{
public bool HasTypeAttribute(),其中tatAttribute:Attribute
{
返回typeof(TType).GetCustomAttribute()!=null;
}
}
公共静态类TypeHelper
{
用于(此T对象)的公共静态类型帮助器
{
返回新的TypeHelperFor();
}
}
//理想,但没有得到支持
HasTypeAttribute(实例);
//锁链
例如.hastypetAttribute();
//直接向前/非链式
HasTypeAttribute(实例);
对于这种情况,这应该是可行的,但我警告不要在最终方法返回void的情况下使用它,因为如果不使用返回值,很容易留下半链

e、 g

//如果我忘了在这里完成链。。。
if(TypeHelper.For(instance))//编译器错误
//但如果我忘记了上一次关于副作用的电话,比如:
//DbHelper.For(table.Execute();
DbHelper.For(表);//幸福地编译,但什么也不做
//而非链接版本可以保护我
DbHelper.Execute(表);

您只需传入一个
对象
,然后使用
obj.GetType
而不是
typeof(TType)
@juharr,这样做不会得到相同的结果。@JonHanna为什么不呢?如果对象的类型与泛型类型相同,那么它应该可以工作。@ThomasFlinkow我的意思是您将拥有
公共bool HasTypeAttribute(object obj)
。基本上它不能做parial泛型推断。它必须推断出所有对象,或者必须指定所有对象。@juharr,如果对象与泛型类型不同,则其工作方式会有所不同。只有当对象的实际具体类型(
object.GetType()
)与编译器从中推断的表达式类型匹配时,它们才会相同,如果该类型是基类型或接口,则情况就不会相同。
public void Demo<T>(T obj)
{
}
Foo.Demo(new Bar());
Foo.Demo<Bar>(new Bar());
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);
// 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);