C# 使用具有不同约束的泛型类
我有两个传统的C#用户控件需要一起工作。 我有一个现有的对话框,需要在其中添加一个现有的通用usercontrol 我尝试了下面的层次结构示例C# 使用具有不同约束的泛型类,c#,generics,C#,Generics,我有两个传统的C#用户控件需要一起工作。 我有一个现有的对话框,需要在其中添加一个现有的通用usercontrol 我尝试了下面的层次结构示例 interface Foo<T> {} interface Bar<T> { T DataObject { get; set; } } public class ClassA<T> where T : Foo<T> { public ClassA(T dataObject) {
interface Foo<T> {}
interface Bar<T>
{
T DataObject { get; set; }
}
public class ClassA<T> where T : Foo<T>
{
public ClassA(T dataObject)
{
//Do stuff if T implements Bar<T> - Pseudocode ahead
if(var T is Bar<T>)
{
var x = new ClassB<T>();
//x is typesafe, and I can set DataObject
x.DataObject = dataObject;
}
}
}
public class ClassB<T> where T : Bar<T>
{
T DataObject { get; set; }
}
如果我创建一个ClassA
的实例,即T
在特定的实例中是ClassC
-那么在代码中有没有一种方法可以使用T
创建ClassB
的实例-在这种情况下ClassA
中的T
符合ClassB
的约束,因为T
是ClassC
我还没有弄明白怎么做,或者如果可能的话——我倾向于相信我做不到
正如我在上面所写的,我有一个基于反射的解决方案,我只是不喜欢使用反射和只获得运行时验证。但是在这种情况下,对于需要一起工作的两个遗留对象,我可能已经没有选择了 首先,你的类型有点奇怪。它们是递归的,
ClassB
需要一个T
来实现Bar
,它的结构与ClassB
相同。也许您想用ClassB
来实现Bar
,而不是要求它作为类型参数
无论如何,你不能这样做。为了能够编写
ClassB
,编译器需要确保T
在运行时是ClassB
的有效类型参数。只有当T
的ClassA
上的类型参数至少与ClassB
中的类型参数一样严格时,才会出现这种情况
不幸的是,即使是一个可以确保这种情况的硬类型检查也不允许您编写ClassB
因此,如果不能编写ClassB
,就无法在编译时获得静态类型安全性。因此,即使您创建了ClassB
(您可以)的实例,您也无法访问该实例上的DataProperty
,因为您无法将其转换为ClassB
因此,为了解决这个问题,您要么只能使用反射来访问DataProperty
,要么调用ClassA
中具有类型约束的方法。我将向您展示这两种解决方案:
public class ClassA<T>
where T : Foo<T>
{
public ClassA(T dataObject)
{
if (typeof(Bar<T>).IsAssignableFrom(typeof(T)))
{
// method 1, calling a generic function
MethodInfo mi = typeof(ClassA<T>).GetMethod("SetBDataObject").MakeGenericMethod(typeof(Bar<T>));
mi.Invoke(this, new object[] { dataObject });
// method 2, doing it all with reflection
Type type = typeof(ClassB<>).MakeGenericType(typeof(T));
object x = Activator.CreateInstance(type);
type.GetProperty("DataObject").SetValue(x, dataObject);
}
}
public object SetBDataObject<TB> (TB obj)
where TB : Bar<TB>
{
var x = new ClassB<TB>();
x.DataObject = obj;
return x;
}
}
公共类ClassA
T:Foo在哪里
{
公共类A(T数据对象)
{
if(typeof(Bar).IsAssignableFrom(typeof(T)))
{
//方法1,调用泛型函数
MethodInfo mi=typeof(ClassA).GetMethod(“SetBDataObject”).MakeGenericMethod(typeof(Bar));
调用(这个,新对象[]{dataObject});
//方法2,通过反射来完成这一切
Type Type=typeof(ClassB)。MakeGenericType(typeof(T));
对象x=Activator.CreateInstance(类型);
type.GetProperty(“DataObject”).SetValue(x,DataObject);
}
}
公共对象数据对象(TB obj)
TB:Bar在哪里
{
var x=新类b();
x、 DataObject=obj;
返回x;
}
}
代码中可能会混淆的第一件事是,您在两个类ClassA
和ClassB
中使用了相同的字母T
作为类型参数
首先,我将陈述显而易见的:当您调用
var x=new ClassB()时
此处T
的约束在ClassA
的上下文中(即T:Foo
),而newclassb()
期望T
与T:Bar
的约束匹配
在我看来,您遇到的问题的根本原因是设计问题。看起来您有点混淆了类型
和类
让我们走一遍:从: 对象的类定义了对象的实现方式 定义对象的内部状态及其实现 行动 相反,对象的类型仅指其接口-集合 它可以响应的请求的数量 一个对象可以有多种类型,不同类的对象可以有多种类型 同样的类型 在代码中使用接口意味着针对
类型进行编码(这很好!)。
检查if(dataObject是Bar)
并在结果构建ClassB
where!typeof(U).Equals(typeof(T)
表示严重依赖于实现(例如类
)
如果你问我,我认为你应该尝试以下方法之一:
使用用于构造ClassB
。在专用工厂中,您可以添加更多的逻辑和验证,以决定如何构造它(根据您的代码,由于类型不匹配,因此不清楚…)
如果可能,解决Foo
和Foo
之间的关系,并在接口中声明约束。在这种情况下,两个接口应具有相同的约束ftoT
您的代码将不会编译-ClassB
不包含DataObject
的定义。这可能是可能的,但与您现在的构造不同。DataObject是Bar
上的属性,而不是ClassB
,您的if语句可能应该包含if(DataObject是Bar){var dataObjectBarT=dataObject as Bar;
这将使您的dataObject成为一个Bar
,但不清楚您接下来要寻找的是什么。代码经过编辑,因此B显式定义了dataObject属性。我有一个实现了Foo和Bar的ClassC在C#中如何具有多态性?Foo和Bar是接口您的观察是某种程度上是正确的。由于我使用的是两个遗留组件,它们的类与类型焦点有所不同。我无法轻松修复ad.2,因为这是遗留组件,两种类型都需要相当多的时间来重新构造。ad.1.实际上是一点o
public class ClassA<T>
where T : Foo<T>
{
public ClassA(T dataObject)
{
if (typeof(Bar<T>).IsAssignableFrom(typeof(T)))
{
// method 1, calling a generic function
MethodInfo mi = typeof(ClassA<T>).GetMethod("SetBDataObject").MakeGenericMethod(typeof(Bar<T>));
mi.Invoke(this, new object[] { dataObject });
// method 2, doing it all with reflection
Type type = typeof(ClassB<>).MakeGenericType(typeof(T));
object x = Activator.CreateInstance(type);
type.GetProperty("DataObject").SetValue(x, dataObject);
}
}
public object SetBDataObject<TB> (TB obj)
where TB : Bar<TB>
{
var x = new ClassB<TB>();
x.DataObject = obj;
return x;
}
}