我有一个通用接口(MyInterface<T>
),它由以下示例中的类ChildA
实现:
public interface MyInterface<T>
{
MyObj<T> GetObj(); // Irrelevant
}
class ChildA : MyInterface<ChildA>
{
// Irrelevant:
MyObj<ChildA> GetObj() {
return new MyObj<ChildA>();
}
}
这样做有效,但我需要确保<T>
始终具有实现类的类型,因此在这种情况下T
应始终为{{1}类型1}},因为它是由ChildA
实现的。
另一个 正确的 实施可能是这样的,例如:
ChildA
但目前,这种 不正确的 实施也是可能的,但它不应该是:
class ChildB : MyInterface<ChildB> { ... }
有没有办法强制执行此操作?
答案 0 :(得分:7)
您不能强制将泛型类型参数约束为实现类型。
可用的type constraints如下:
where T : struct
where T : class
where T : new()
where T : <base class name>
where T : <interface name>
where T : U
C#中没有像where T : self
这样的东西。实际上,它甚至没有意义,因为这样的事情不能有意义地执行。此外,它根本不适合协方差/逆变概念,并且一般来说很难继承。
你最接近的是:
public interface IMyInterface<T> where T : IMyInterface<T>
{
MyObj<T> GetObj();
}
让我们说你可以这样做:
public interface IMyInterface<T> where T : self // this syntax does not exist in C#
{
MyObj<T> GetObj();
}
现在所有实现类型都必须使用自己作为类型参数。但你仍然可以这样做:
public class ChildC<T> : IMyInterface<T> where T : self
{
/* ... */
}
这将绕过你的限制。
答案 1 :(得分:2)
有没有办法强制执行此操作?
好吧,不是通用约束。你可以用反思做到这一点虽然我投反对票:
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<table>
<tr class="table-row">
<td>
<a href="#" class="item-name">Item 1</a>
<input type="text" value="[item]" class="input-item" id="item-1">
</td>
<td>
<a href="#" class="item-name">Price 1</a>
<input type="text" value="[item]" class="input-item" id="price-1">
</td>
<td><a href="#" class="edit-button">Edit</a></td>
</tr>
<tr class="table-row">
<td>
<a href="#" class="item-name">Item 2</a>
<input type="text" value="[item]" class="input-item" id="item-2">
</td>
<td>
<a href="#" class="item-name">Price 2</a>
<input type="text" value="[item]" class="input-item" id="price-2">
</td>
<td><a href="#" class="edit-button">Edit</a></td>
</tr>
</table>
示例:
public abstract class BaseChild<T> : MyInterface<T>
{
protected BaseChild()
{
if (typeof(T) != this.GetType())
{
throw new InvalidOperationException(string.Format(
"Type {0} is not supported as valid type parameter for type {1}",
typeof(T).Name, this.GetType().Name));
}
}
}
class ChildA : BaseChild<int> { }
// Bang! throws
var instance = new ChildA();
答案 2 :(得分:1)
您无法执行此操作,但您可以创建自己的控件,比较界面的泛型类型和类的类型。参见示例:
class ChildA : MyInterface<ChildB>
{
public ChildA()
{
this.ValidateGenericType();
}
public MyObj<ChildB> GetObj()
{
return new MyObj<ChildB>();
}
protected void ValidateGenericType()
{
//throws an Exception because ChildB is different of ChilA
if (this.GetType().Name != this.GetType().GetInterfaces()[0].GetGenericArguments()[0].Name)
{
throw new Exception("The generic type must be of type ChildA.");
}
}
}
答案 3 :(得分:1)
您似乎应该使用扩展方法而不是为此目的强制执行某些接口
public interface ISomeInterface {}
public class Child: ISomeInterface {}
public class OtherChild : ISomeInterface { }
public static class MyInterfaceExtensions
{
public static MyObj<T> GetMyObj<T>(this T child) where T : ISomeInterface
{
return new MyObj<T>();
}
}
public static class Test
{
public static void RunTest()
{
var child = new Child();
var otherChild = new OtherChild();
MyObj<Child> myObj = child.GetMyObj();
MyObj<OtherChild> myOtherObj = otherChild.GetMyObj();
}
}