对于C#,是否可以在泛型类的实例声明中指定类型约束?

时间:2017-08-31 22:29:40

标签: c# generics types

我想带两个具有共享层次结构的对象,它们都实现一个接口,并将它们放在一个容器中,例如List,通常采用单一类型参数。我在这个问题中使用了非编译代码,因为我找不到C#的一个功能,它可以让我在编译时做我想问的事情。

所以,设置如:

public class DataObject
{
    int property;
}

public interface IWriteData
{
    void WriteData();
}

public class A : DataObject, IWriteData, IDoSomethingElseA
public class B : DataObject, IWriteData, IDoSomethingElseB

和代码:

var x = new A();
var y = new B();
List<T> where T : (DataObject, IWriteData) mySharedContainer = new List<T>;
T.Add(x);
T.Add(y);

上面的列表声明行不起作用,但是我能想到的最接近我的目标。我的预感是,这不是目前能够完成的事情,我需要:

  • 定义一个他们可以继承的共享类,并且还实现了接口(在这种情况下我不想做,因为这不是我的代码库,我试图尽量减少占用空间) )
  • 进行运行时类型转换,并失去编译时的好处 类型检查
  • 通过编写处理类型A的代码和处理类型B的代码来复制代码。

但是,我会非常高兴地发现其他情况。在考虑它时,我看不出任何直接的理由,理论上,编译器不能在该行说“好吧,从现在开始我将检查添加到该列表的所有内容是否继承自该类并实现这些接口。“

谢谢!

3 个答案:

答案 0 :(得分:8)

您想要的功能称为交集类型,而C#对交集类型的支持非常非常有限。事实上,只有一种方法可以指定类型限制,就是这样:

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="clickmeDIV">

  <script>
    $(document).on('click', '#clickmeDIV', function() {

      alert('Alert executed by the original script');
      $('#clickmeDIV').empty();

      $('#clickmeDIV').html('<script type="text/javascript">' +
        '$(document).on("click","#clickmeDIV", function(){' +
        'var foo  = function(){alert("Alert executed by the script inserted dynamically"); }; foo();' +
        '}); </s' + 'cript>');

    });
  </script>

</div>

class C { public static void M<T>(T t) where T : DataObject, IWriteData { List<T> myList = new List<T>() { t }; // With this restriction we can make both these conversions: IEnumerable<DataObject> iedo = myList; // Legal IEnumerable<IWriteData> iewd = myList; // Legal } } 仅限于实现T的类型的交集中的类型以及扩展IWriteData的类型。

但这并没有解决你遇到的问题。在此解决方案中,我们可以调用DataObjectM<A>并获取M<B>的列表,其中T绝对是TDataObject。但你必须 IWriteData是什么。 T可以是T,也可以是A,但B不能是TA&#34;。 (和&#34; A或B&#34;将是联合类型。)

  

在考虑它的时候,我无法看到任何直接的理由,从理论上讲,编译器无法在那条线上说#34;好吧,从现在开始我会检查所有添加的内容此列表继承自 object 类并实现这些接口。&#34;

Objects 是类的实例;类扩展类,而不是对象。)

你是对的;没有理论上的理由。有些语言支持union和intersection类型; Hack,我现在使用的语言,就是这样一种语言。 TypeScript也支持这种类型的输入。但是C#不是其中之一,对不起。

答案 1 :(得分:1)

这是不可能的。

在C#中,你只能为字段,方法,属性等指定一种类型。这就是泛型无法做到这一点的原因。泛型只是编译为您使用的每种类型组合的单独的类/方法。

您必须在类中实现接口或继承接口,以便您只需指定一个接口。

答案 2 :(得分:-1)

我不是百分之百确定你想要达到的目标

List<T> where T : (DataObject, IWriteData) mySharedContainer = new List<T>;

由于某些原因不可能。首先,我们不能指定内联泛型,如果我们可以List<T>类型不接受两个类型参数。

然而,正如我所看到的,你可以有效地创建另一个界面说

public interface ISharedObject
{
    int Property { get; set; }

    void WriteData();
}

然后您只需将您的类修改为:

public class A : DataObject, IWriteData, ISharedObject, IDoSomethingElseA
{
    public void WriteData();
}

public class B : DataObject, IWriteData, ISharedObject, IDoSomethingElseB
{
    public void WriteData();
}

因此,界面ISharedObject同时包含PropertyWriteData()个签名。 DataObject实现Property(注意我将其更改为属性而不是字段)。然后,接口IWriteData定义WriteData方法的合同。因此两者都会编译。

现在您有一个类型参数,可以调用

var x = new A();
var y = new B();
var list = new List<ISharedObject>();
list.Add(x);
list.Add(y);

如果我误解了您的要求,请提前预测。