C# 会";“受约束类型”;在VB/C中有用吗? 简介
Marc Gravell建议我在这个网站上发布新的语言功能建议,以收集对这些建议的总体意见 我的想法是收集他们是否有帮助,或者是否已经有另一种方法来实现我所追求的目标 建议(受限类型) VB.Net中的正常变量声明是这样编写的:C# 会";“受约束类型”;在VB/C中有用吗? 简介,c#,vb.net,types,constraints,C#,Vb.net,Types,Constraints,Marc Gravell建议我在这个网站上发布新的语言功能建议,以收集对这些建议的总体意见 我的想法是收集他们是否有帮助,或者是否已经有另一种方法来实现我所追求的目标 建议(受限类型) VB.Net中的正常变量声明是这样编写的: Dim SomeVariable as SomeType 我建议允许使用以下表格 此语法借用了Vb.Net的约束泛型风格 为什么允许这样?…它有什么好处? 我最初想到的具体案例是定义一个特定的控件子集。 我希望为一系列控制工厂创建一个接口,这些工厂将根据一些业务规则提
Dim SomeVariable as SomeType
我建议允许使用以下表格
此语法借用了Vb.Net的约束泛型风格
为什么允许这样?…它有什么好处?
我最初想到的具体案例是定义一个特定的控件子集。
我希望为一系列控制工厂创建一个接口,这些工厂将根据一些业务规则提供控制
这些控件的使用者将通过接口要求创建的所有控件也应实现一些系列的接口(在我的情况下只有一个),这些接口为所有这些控件提供了正常控件中通常没有的附加功能
值得注意的是,以下各项目前不起作用
Public Interface ISpecialControl
End Interface
Public Interface IControlProvider
Function CreateControl(Of T As {Control, ISpecialControl})() As T
End Interface
Public Class SpecialTextBoxProvider
Implements IControlProvider
Public Function CreateControl(Of T As {Control, ISpecialControl})() As T Implements IControlProvider.CreateControl
Return New SpecialTextBox
End Function
End Class
Public Class SpecialTextBox
Inherits TextBox
Implements ISpecialControl
Public Sub New()
End Sub
End Class
我认为这可以翻译成C#作为:
我意识到我的工厂可以返回简单的控件,我可以在运行时检查它们是否实现了ISpecialControl,但这会产生运行时问题,我宁愿在编译时检查,因为这是一种逻辑上的可能性,即使目前不是一种实际的可能性
更新:想法是这些工厂可以位于外部(甚至可能是第三方)程序集中,并且可以依赖于他们想要的任何控件库,创建并返回这些控件的派生控件,这些控件也实现了ISpecialControl
这些程序集可以通过自配置反射(第一次通过反射后进行配置,然后在后续运行中使用)定位,并且调用程序集可以在不知道这些控件的依赖性的情况下使用这些程序集
它确实要求这些工厂是可构造的,而无需传递有关它们预期调用的控件的信息,因为这将违背这一点
那么你认为。。。这有用吗?。。。有没有更好的方法来实现这一点?已经有办法做到这一点了吗?与其说是“受约束的类型”,不如说是“受约束的变量”——但肯定很有趣。与泛型约束一样,如果存在冲突的成员,可能会在解决方案方面存在一些小问题,但可能会采用与泛型约束相同的解决方法
当然,务实的观点是,您已经可以使用etc,但是您需要使这两个引用彼此保持最新
嗯。。。有趣。使用界面合成怎么样 你有
interface IA;
class B;
如果存在,则使用类B的接口并生成复合
interface IB;
interface IAB : IA, IB;
修改类
class C : B, IA
实现复合接口(不应出现问题)
您可以使用接口IAB作为约束类型。我不明白您的建议,我认为这是我的问题 然而,在我看来,这似乎是您想要返回一个实现特定接口的控件 为什么不能说这个方法返回那个特定的接口呢?我听上去就像你们说的“我想返回从控件派生的类,它也实现了接口” 也许解决方案是将需要的控件部分提取到自己的接口中,并指定要返回实现这两个部分的对象 像这样:
interface IControl { ... }
interface ISomeInterface { ... }
interface IControlInterface : IControl, ISomeInterface { ... }
最后一个接口将指定您需要一个实现两个基本接口的对象,这听起来像是您想要的,只是您希望其中一个需求是基类,而不是接口
我认为您可以通过使用接口来解决这一问题。我认为,虽然表面上很有用,但这种事情最好由以下两种方式之一来处理:
- Duck通过dynamic(将于VS2010发布)键入,尽管消除了类型安全性,但灵活性大大提高
- 一般成分
public interface IControlProvider<T>
where T : Control, ISpecialControl
{
T CreateControl();
}
public class SpecialTextBoxProvider : IControlProvider<SpecialTextBox>
{
public SpecialTextBox CreateControl()
{
return new SpecialTextBox();
}
}
公共接口IControlProvider
式中T:控制,IsSpecialControl
{
T CreateControl();
}
公共类SpecialTextBoxProvider:IControlProvider
{
公共SpecialTextBox CreateControl()
{
返回新的SpecialTextBox();
}
}
事实上,鉴于大多数控件都有一个默认的公共构造函数,您可以让它变得更简单:
public class ControlProvider : IControlProvider<T>
where T : Control, ISpecialControl, new()
{
public T CreateControl()
{
return new T();
}
}
var control = ControlProvider<SpecialTextBox>.CreateControl();
公共类ControlProvider:IControlProvider
其中T:Control,ISpecialControl,new()
{
公共创建控件()
{
返回新的T();
}
}
var control=ControlProvider.CreateControl();
如果对调用代码不直接获取SpecialTextBox上的引用依赖项有额外的限制,那么这将不起作用。这与?为什么不扩展控件?编辑:哦,等等,我没有正确阅读,这是关于将其限制为2种类型,而不是选择2种类型。我想你可以像下面提到的课一样解决这个问题 我曾经用一个类来模拟这种行为:
public class Choice<T1, T2>
{
private readonly T1 value1;
private readonly T2 value2;
public Choice(T1 value)
{
value1 = value;
}
public Choice(T2 value)
{
value2 = value;
}
public static implicit operator T1(Choice<T1, T2> choice)
{
return choice.value1;
}
public static implicit operator T2(Choice<T1, T2> choice)
{
return choice.value2;
}
public static implicit operator Choice<T1, T2>(T1 choice)
{
return new Choice<T1, T2>(choice);
}
public static implicit operator Choice<T1, T2>(T2 choice)
{
return new Choice<T1, T2>(choice);
}
public T1 Value1
{
get { return value1; }
}
public T2 Value2
{
get { return value2; }
}
}
公共类选择
{
私有只读T1值1;
私有只读T2值2;
公共选择(T1值)
{
value1=值;
}
公共选择(T2值)
{
value2=值;
}
公共静态隐式运算符T1(选择)
{
返回选项1;
}
公共静态隐式运算符T2(选择)
{
返回选项2;
}
公共静态隐式运算符选择(T1选择)
{
返回新选项(Choice);
}
公共静态隐式运算符选择(T2选择)
{
返回新选项(Choice);
}
interface IControl { ... }
interface ISomeInterface { ... }
interface IControlInterface : IControl, ISomeInterface { ... }
public interface IControlProvider<T>
where T : Control, ISpecialControl
{
T CreateControl();
}
public class SpecialTextBoxProvider : IControlProvider<SpecialTextBox>
{
public SpecialTextBox CreateControl()
{
return new SpecialTextBox();
}
}
public class ControlProvider : IControlProvider<T>
where T : Control, ISpecialControl, new()
{
public T CreateControl()
{
return new T();
}
}
var control = ControlProvider<SpecialTextBox>.CreateControl();
public class Choice<T1, T2>
{
private readonly T1 value1;
private readonly T2 value2;
public Choice(T1 value)
{
value1 = value;
}
public Choice(T2 value)
{
value2 = value;
}
public static implicit operator T1(Choice<T1, T2> choice)
{
return choice.value1;
}
public static implicit operator T2(Choice<T1, T2> choice)
{
return choice.value2;
}
public static implicit operator Choice<T1, T2>(T1 choice)
{
return new Choice<T1, T2>(choice);
}
public static implicit operator Choice<T1, T2>(T2 choice)
{
return new Choice<T1, T2>(choice);
}
public T1 Value1
{
get { return value1; }
}
public T2 Value2
{
get { return value2; }
}
}
[TestMethod]
public void TestChoice()
{
TestChoice("Hello");
TestChoice(new []{"Hello","World"});
}
private static void TestChoice(Choice<string[], string> choice)
{
string value = choice;
string[] values = choice;
if (value != null)
Console.WriteLine("Single value passed in: " + value);
if (values != null) {
Console.WriteLine("Multiple values passed in ");
foreach (string s in values)
Console.WriteLine(s + ",");
}
}