限制一个泛型类型参数有一个特定的构造 [英] Restricting a generic type parameters to have a specific constructor

查看:107
本文介绍了限制一个泛型类型参数有一个特定的构造的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道为什么只能不带参数适用于泛型类型参数的新的约束,也就是说,人们可以约束的类型有参数的构造函数,但一个人不能约束类有,比方说,接收一个INT作为参数的构造函数。我知道解决这个途径,使用反射或工厂模式,工作正常,正常。但我真的很想知道为什么,因为我一直在想这个问题,我实在想不出有证明有理由对新的约束这种限制参数参数的构造函数和1之间的差别。我在想什么?
非常感谢

I'd like to know why the new constraint on a generic type parameter can only be applied without parameters, that is, one may constraint the type to have the parameterless constructor, but one cannot constraint the class to have, say, a constructor that receives a int as a parameter. I know ways around this, using reflection or the factory pattern, that works fine, ok. But I'd really like to know why, because I've been thinking about it and I really can't think of a difference between a parameterless constructor and one with parameters that would justify this restriction on the new constraint. What am I missing? Thanks a lot

@Eric:让我去这里与你一道秒:

@Eric: Let me go here with you for a sec:

构造函数是方法

然后我想,如果我是这样的,没有人会反对:

Then I suppose no one would object if I'd go like this:

public interface IReallyWonderful
{
    new(int a);

    string WonderMethod(int a);
}

但是,一旦我有,那么我会去:

But once I have that, then I'd go:

public class MyClass<T>
        where T : IReallyWonderful
{
    public string MyMethod(int a, int b)
    {
        T myT = new T(a);
        return myT.WonderMethod(b);
    }
}

这就是我想要的东西摆在首位的事情。所以,很抱歉,但没有,构造函数不是方法,或至少不完全是。

在实现此功能的困难,以及我真的不知道,即使我这样做,我不会有什么就有关股东资金支出明智的决定说。这样的事情,我会一直标记为答案的时候了。

On the difficulties of implementing this feature, well I'd really wouldn't know, and even if I did, I wouldn't have anything to say on a decision regarding the wisely expenditure of shareholder money. Something like that, I would've marked as an answer right away.

但从学术(我的)点,即没有实施任何费用方面,真正的问题是(我已经四舍五入它该在最后几个小时):

From an academic (my) point of view, and that is, without any regards for implementation costs, the question really is (I've rounded it up to this in the last few hours):

构造应该被看作是一个类的实现的一部分,或作为语义合同(以同样的方式的接口被认为是语义契约)的一部分。

Should constructors be considered as part of the implementation of a class, or as part of the semantic contract (in the same way an interface is considered a semantic contract).

如果我们考虑构造作为实施的一部分,那么,制约一个泛型类型参数的构造函数是不是做一个非常通用的东西,因为这会是你的泛型类型捆绑到具体实施,一个几乎可以说的为什么使用泛型呢?

If we consider constructors as part of the implementation, then, constraining the constructor of a generic type parameter is not a very generic thing to do, since that'd be tying up your generic type to a concrete implementation, and one almost could say why use generics at all?

构造函数的例子作为执行工作的一部分(在指定任何下面的构造函数所界定语义合同的一部分,没有任何意义 ITransformer

Example of constructor as part of the implementation (no sense in specifying any of the following constructors as part of the semantic contract defined by ITransformer):

public interface ITransformer
{
    //Operates with a and returns the result;
    int Transform(int a);
}

public class PlusOneTransformer : ITransformer
{
    public int Transform(int a)
    {
        return a + 1;
    }
}

public class MultiplyTransformer : ITransformer
{
    private int multiplier;

    public MultiplyTransformer(int multiplier)
    {
        this.multiplier = multiplier;
    }

    public int Transform(int a)
    {
        return a * multiplier;
    }
}

public class CompoundTransformer : ITransformer
{
    private ITransformer firstTransformer;
    private ITransformer secondTransformer;

    public CompoundTransformer(ITransformer first, ITransformer second)
    {
        this.firstTransformer = first;
        this.secondTransformer = second;
    }

    public int Transform(int a)
    {
        return secondTransformer.Transform(firstTransformer.Transform(a));
    }
}

的问题是,构造也可被视为语义合同的一部分,像这样:

The problem is that constructors may also be considered as part of the semantic contract, like so:

public interface ICollection<T> : IEnumerable<T>
{
    new(IEnumerable<T> tees);

    void Add(T tee);

    ...
}

这意味着,它总是更多钞票从一个元素序列构建一个集合,对不对?这将使语义合同的一个非常有效的部分,对吧?

This means, it's always posible to build a collection from a sequence of elements, right? And that would make a very valid portion of a semantic contract, right?

我,不考虑任何关于股东的钱明智地支出方面,将有利于使构造语义合同的组成部分。一些开发商起来和约束某些类型的食堂到具有语义上不正确的构造函数,那么,从相同的开发者加入了语义上不正确的操作区别在那里?毕竟,语义合同​​,因为我们都认为是这样,因为我们所有的记录我们的图书馆真的很好;)

Me, without taking into account any of the aspects regarding the wisely expenditure of shareholder money, would favour allowing constructors as parts of semantic contracts. Some developer messes it up and constraints a certain type to having a semantically incorrect constructor, well, what's the difference there from the same developer adding a semantically incorrect operation? After all, semantic contracts are that, because we all agreed they are, and because we all document our libraries really well ;)

@supercat是一直试图设置一些例子,如何(引自评论)

@supercat is been trying to set some examples as how (quote from a comment)

这也将是很难准确定义构造函数的约束应该如何工作,而不会导致奇怪的行为。

但我真的不同意必须。在C#中(当然,在.NET中)惊喜,如如何使企鹅飞?根本就不会发生。有pretty简单的规则,对编译器如何解析方法调用,如果编译器无法解决这个问题,那么,它不会通过,将无法编译即是。

but I really must disagree. In C# (well, in .NET) surprises like "How to make a penguin fly?" simply don't happen. There are pretty straightforward rules as to how the compiler resolves method calls, and if the compiler can't resolve it, well, it won't pass, won't compile that is.

他最后的例子是:

如果他们是逆变,再一个遇到麻烦解决它的构造,如果一个泛型类型有约束新的(猫,ToyotaTercel)应该被调用,实际类型只是有构造新的(动物,ToyotaTercel)和新(猫,汽车)。

好吧,让我们试试这个(这在我看来是一个类似的情况,通过@supercat提议)

Well, lets try this (which in my opinion is a similar situation to that proposed by @supercat)

class Program
{
    static void Main(string[] args)
    {
        Cat cat = new Cat();
        ToyotaTercel toyota = new ToyotaTercel();

        FunnyMethod(cat, toyota);
    }

    public static void FunnyMethod(Animal animal, ToyotaTercel toyota)
    {
        Console.WriteLine("Takes an Animal and a ToyotaTercel");
    }

    public static void FunnyMethod(Cat cat, Automobile car)
    {
        Console.WriteLine("Takes a Cat and an Automobile");
    }
}

public class Automobile
{ }

public class ToyotaTercel : Automobile
{ }

public class Animal
{ }

public class Cat : Animal
{ }

和,哇,它不会有错误编译

And, wow, it won't compile with the error

在调用以下方法或属性之间暧昧:TestApp.Program.FunnyMethod(TestApp.Animal,TestApp.ToyotaTercel)'和'TestApp.Program.FunnyMethod(TestApp.Cat,TestApp.Automobile)

The call is ambiguous between the following methods or properties: 'TestApp.Program.FunnyMethod(TestApp.Animal, TestApp.ToyotaTercel)' and 'TestApp.Program.FunnyMethod(TestApp.Cat, TestApp.Automobile)'

我不明白为什么,如果同样probleme引起了溶液与参数的构造函数约束,喜欢的结果应该是不同的,因此:

I don't see why the result should be different if the same probleme arouse out of a solution with parameterized constructor constraints, like so:

class Program
{
    static void Main(string[] args)
    {
        GenericClass<FunnyClass> gc = new GenericClass<FunnyClass>();
    }
}

public class Automobile
{ }

public class ToyotaTercel : Automobile
{ }

public class Animal
{ }

public class Cat : Animal
{ }

public class FunnyClass
{
    public FunnyClass(Animal animal, ToyotaTercel toyota)
    {            
    }

    public FunnyClass(Cat cat, Automobile car)
    {            
    }
}

public class GenericClass<T>
   where T: new(Cat, ToyotaTercel)
{ }

现在,当然,编译器无法处理在构造函数中的约束,但如果它可以,为​​什么便无法错误是,就行了 GenericClass&LT; FunnyClass&GT; GC =新GenericClass&LT; FunnyClass&GT;(); 类似于获得试图编译第一个例子时,该的 FunnyMethod

Now, of course, the compiler can't handle the constraint on the constructor, but if it could, why could't the error be, on the line GenericClass<FunnyClass> gc = new GenericClass<FunnyClass>(); similar to that obtained when trying to compile the first example, that of the FunnyMethod.

不管怎样,我会走一步。当一个重写的抽象方法或者实现一个接口上定义的方法,需要一个具有完全相同的参数类型,不允许有继承人或祖先这样做。所以,当需要一个参数化的构造,要求应该具有精确定义满足,不与任何其他。在这种情况下,类 FunnyClass 不可能被指定为类型,泛型参数类型的类 GenericClass

Anyway, I'd go one step further. When one overrides an abstract method or implements a method defined on an interface, one is required to do so with exactly the same parameters type, no inheritors or ancestors allowed. So, when a parameterized constructor is required, the requirement should be met with an exact definition, not with anything else. In this case, the class FunnyClass could never be specified as the type, for the generic parameter type of class GenericClass.

推荐答案

当然,从我柯克沃尔的报价是所有需要的理由;我们不需要提供理由功能的的存在。产品特点具有巨大的成本。

Kirk Woll's quote from me of course is all the justification that is required; we are not required to provide a justification for features not existing. Features have enormous costs.

然而,在这种特定情况下,我当然可以给你一些原因,如果它在设计中会作为语言的未来版本可能的功能上来我就回推功能。

However, in this specific case I can certainly give you some reasons why I would push back on the feature if it came up in a design meeting as a possible feature for a future version of the language.

要开始:考虑更多的一般特征。构造函数的方法的。如果你希望那里是一个方式说类型参数必须有一​​个构造函数一个int,那么它​​为什么不也在情理之中说类型参数必须有一​​个公共的方法为q,它有两个整数,并返回一个字符串?

To start with: consider the more general feature. Constructors are methods. If you expect there to be a way to say "the type argument must have a constructor that takes an int" then why is it not also reasonable to say "the type argument must have a public method named Q that takes two integers and returns a string?"

string M<T>(T t) where T has string Q(int, int)
{
    return t.Q(123, 456);
}

这是否让你觉得非常的通用的事是什么?它柜台似乎仿制药的想法有这种约束。

Does that strike you as a very generic thing to do? It seems counter to the idea of generics to have this sort of constraint.

如果该功能是一个坏主意的方法,那么为什么它的的恰巧是构造的想法方法的

If the feature is a bad idea for methods, then why is it a good idea for methods that happen to be constructors?

相反,如果是方法和构造是一个好主意,那为什么要停止呢?

Conversely, if it is a good idea for methods and constructors, then why stop there?

string M<T>(T t) where T has a field named x of type string
{
    return t.x;
}

我说,我们应该为做全功能不这样做,在所有的。如果它能够限制类型有特殊的构造,然后让我们做的全功能的和一般的成员的基础上,限制类的而不是重要的是刚刚的构造

I say that we should either do the whole feature or don't do it at all. If it is important to be able to restrict types to have particular constructors, then let's do the whole feature and restrict types on the basis of members in general and not just constructors.

这的功能当然是贵了不少,设计,实现,测试,文档和维护。

That feature is of course a lot more expensive to design, implement, test, document and maintain.

第二点:假设我们决定实施的功能,无论是刚建设者版或任何成员的版本。 C $ c执行我们产生什么$?有关通用codeGEN的事情是,它经过精心设计,让你可以做静态分析的一次的和做用它。但是,是描述调用了一个int的构造,在IL没有标准的方式。我们将不得不要么添加一个新的概念,IL,或生成code,使通用的构造函数调用使用反射的。

Second point: suppose we decided to implement the feature, either the "just constructors" version or the "any member" version. What code do we generate? The thing about generic codegen is that it has been carefully designed so that you can do the static analysis once and be done with it. But there is no standard way to describe "call the constructor that takes an int" in IL. We would have to either add a new concept to IL, or generate the code so that the generic constructor call used Reflection.

前者是昂贵的;改变的IL的一个基本概念是非常昂贵的。后者是(1)慢,(2)箱参数,(3),你可以自己写code。如果你打算使用反射来找到一个构造函数,并调用它,然后的编写使用反射来找到一个构造函数和称它为code。的如果是code根策略,那么的的约束赋予唯一的好处是,它没有公开的构造函数接受一个int在编译时,而不是运行时被捕获传递一个类型参数的错误的。你没有得到任何的仿制药的其他好处,比如避免反射和拳击的处罚。

The former is expensive; changing a fundamental concept in IL is very costly. The latter is (1) slow, (2) boxes the parameter, and (3) is code that you could have written yourself. If you're going to use reflection to find a constructor and call it, then write the code that uses reflection to find a constructor and call it. If this is the code gen strategy then the only benefit that the constraint confers is that the bug of passing a type argument that does not have a public ctor that takes an int is caught at compile time instead of runtime. You don't get any of the other benefits of generics, like avoiding reflection and boxing penalties.

这篇关于限制一个泛型类型参数有一个特定的构造的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆