Marc Gravell建议我向本网站发布新的语言功能建议以收集关于它们的一般意见,这个问题提示。
想法是收集它们是否有用,或者可能已经有另一种方式来实现我所追求的目标。
因此编写VB.Net中的正常变量声明:
Dim SomeVariable as SomeType
我建议允许以下表格
Dim SomeVariable1 as {SomeType, ISomeInterface}
Dim SomeVariable2 as {SomeType, ISomeInterface, ISomeOtherInterface}
这种语法借鉴了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#:
public interface ISpecialControl
{
}
public interface IControlProvider
{
T CreateControl<T>()
where T : Control, ISpecialControl;
}
public class SpecialTextBoxProvider : IControlProvider
{
public T CreateControl<T>()
where T : Control, ISpecialControl
{
return new SpecialTextBox();
}
}
public class SpecialTextBox : TextBox, ISpecialControl
{
}
由于无法将SpecialTextbox强制转换为T,尝试返回“New SpecialTextbox”失败。
"Value of type 'MyApp.SpecialTextBox' cannot be converted to 'T'"
我意识到我的工厂可以被允许返回简单的控件,我可以在运行时检查它们是否实现了ISpecialControl,但是这会产生运行时问题,我宁愿在编译时检查它,因为它是合乎逻辑的可能性,即使当前不是一个实用的
更新:这个想法是这些工厂可能位于外部(甚至可能是第三方)程序集中,并且可以依赖于他们想要的任何控件库,创建并返回这些控件的衍生产品,这些控件也实现了ISpecialControl。
这些程序集可以通过自我配置 - 反射定位(第一次通过反射,然后进行配置,然后在进一步的运行中使用),并且在调用程序集不知情的情况下使用这些控件将具有的依赖性。 / p>
它确实要求这些工厂是可构造的,而不传递有关他们应该调用的控件的信息,因为那样会破坏这一点。
那么您认为......这会有用吗?...有没有更好的方法来实现这一目标?有没有办法实现这个目标?
答案 0 :(得分:1)
我认为,虽然表面上很有用,但这两种情况之一可以更好地解决这个问题:
您的原始示例既不需要也可以轻松地工作:
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();
鉴于调用代码没有直接对SpecialTextBox进行引用依赖的额外限制,这将无效。
答案 1 :(得分:0)
它比“约束类型”更“受约束的变量” - 但绝对有趣。与通用约束一样,如果存在冲突的成员,可能会有一些较小的分辨率,但是相同的变通方法可能适用于通用约束。
当然,务实的观点是你已经可以投射等了,但是你需要让两个参考文献保持最新...
嗯......有趣。答案 2 :(得分:0)
使用界面组合怎么样?
你有
interface IA;
class B;
如果存在则使用B类的接口并制作复合
interface IB;
interface IAB : IA, IB;
修改课程
class C : B, IA
实现复合接口(不应该出现问题)
class C : B, IAB
您可以使用接口IAB作为约束类型。
答案 3 :(得分:0)
我不明白你提出的建议,我认为这是我的问题。
但是,听起来我想要返回一个实现特定接口的控件。
为什么不能说该方法返回特定的接口?当你说“我想要返回来自Control的类,并且还实现接口ISomeInterface”时,听起来对我来说。
也许解决方案是将您需要的Control部分提取到您自己的界面中,并指定您想要返回实现它们的对象?
像这样:
interface IControl { ... }
interface ISomeInterface { ... }
interface IControlInterface : IControl, ISomeInterface { ... }
这最后一个接口将指定您需要一个实现两个基本接口的对象,这听起来像您想要的,除了您希望其中一个要求是基类而不是接口。
我认为你可以通过使用接口来解决这个问题。
答案 4 :(得分:0)
这与extension methods有很大不同吗?为什么不扩展控件?
答案 5 :(得分:0)
编辑:哦等等我没有正确阅读,这是关于将它限制为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; }
}
}
允许您创建这样的结构:
[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 + ",");
}
}
隐式运算符的缺点是它不会对接口进行隐式转换(它确实可以从接口类型转换),因此传入IEnumerable<T>
而不是string[]
不会在尝试将包含的值从Choice<IEnumerable<T>, T>
转换回IEnumerable<T>
时工作。
通常我更喜欢使用重载/接口BTW,所以不要误解我这里:))
在您使用属性(并且因此不能使用重载)的情况下会更有用,例如DataSource属性,例如只允许list<string>
或list<ListItem>
。
答案 6 :(得分:0)
这似乎是一种有用的语言功能。除了符合多个约束之外,可能有类型未知的方法参数,但是没有办法将这样的参数存储在字段中,以便它可以传递给这样的函数,甚至可以转换为类型。过去了。
然而,还有另一种方法可以实现你所追求的基本结果,尽管它有点笨拙。请参阅我的问题Storing an object that implements multiple interfaces and derives from a certain base (.net),其中提供了我能够制定的最佳方法。