这令我感到困惑,因为我得到了看似矛盾的错误。
我使用泛型,将T
约束为Something
,然后将U
约束为AnOperation<Something>
。
我预计对象AnOperation<Something>
从现在开始被认为是类型U
。但是,我收到了错误:
Cannot implicitly convert type 'ConsoleApp1.AnOperation<T>' to 'U'
这很奇怪。好吧,我试着明确地将它投射到U,然后我收到了这个错误:
Cannot convert type 'ConsoleApp1.AnOperation<T>' to 'U'
也提到Cast is redundant
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
}
}
class MyClass<T, U>
where T : Something
where U : AnOperation<Something>
{
public U GetAnOperationOfSomething()
{
AnOperation<T> anOperation = new AnOperation<T>();
return anOperation; // Cannot implicitly convert type 'ConsoleApp1.AnOperation<T>' to 'U'
// return (U)anOperation; // Cannot convert type 'ConsoleApp1.AnOperation<T>' to 'U' also Cast is redundant
}
}
public class Something
{
}
public class AnOperation<T>
where T : Something
{
}
}
这里发生了什么?
编辑:我试图了解语言级别的问题,而不是寻找实际问题的解决方法。
答案 0 :(得分:11)
你的约束几乎是正确的,但并不完全。你定义
where U : AnOperation<Something>
但是你创建了
AnOperation<T> anOperation = new AnOperation<T>()
这不是一回事。如果您将约束更改为...
where U : AnOperation<T>
......你会没事的。
另一个问题是,虽然U
每个AnOperation<T>
都是AnOperation<T>
,但并非每个U
都是public U GetAnOperationOfSomething()
。当你申报......
U
...您正在保证该方法返回的是AnOperation<T>
。 U
无法满足这种保证。
您正在使用U
的类型转换解决此问题。这违反了泛型类的目的,因为每个AnOperation<T>
必须是U
,否则您将获得运行时异常。这使得整个类型参数U
变得不必要。您实际想要做的是创建new()
。您可以使用class MyClass<T, U>
where T : Something
where U : AnOperation<T>, new()
{
public U GetAnOperationOfSomething()
{
U anOperation = new U();
//...
return anOperation;
}
}
约束:
new()
U
约束保证new
将有一个公共默认构造函数,您可以调用它。
答案 1 :(得分:5)
T
是继承自Something
的任何类。
U
是继承自AnOperation<Something>
的任何类。假设您有这样的子类:
public class ChildOperation<T> : AnOperation<T> {}
现在您的U
可能是ChildOperation<Something>
,并且您无法返回父类(AnOperation<T>
)的实例作为子类的实例(U
,即ChildOperation<Something>
})。 T
确实ChildSomething
时可能会出错,因为AnOperation<Something>
无法隐式转换为AnOperation<ChildSomething>
。长话短说 - AnOperation<T>
确实无法始终转换为您的U
类型,因此编译器是正确的。
答案 2 :(得分:1)
只是为了支持@Evk的回答。见这个例子。
class Program
{
static void Main(string[] args)
{
MyClass<SomeSomething, AnOperation<Something>> foo =
new MyClass<SomeSomething, AnOperation<Something>>();
// AnOperation<SomeSomething> will cause a compile error.
var bar = foo.GetAnOperationOfSomething();
Console.WriteLine(bar != null);
Console.Read();
}
}
class MyClass<T, U>
where T : Something
where U : AnOperation<Something>
{
public U GetAnOperationOfSomething()
{
U anOperation = Activator.CreateInstance<U>();
return anOperation;
}
}
public class Something
{
}
public class AnOperation<T>
where T : Something
{
}
public class SomeSomething : Something
{
}
答案 3 :(得分:1)
如果从AnOperation
类切换到IAnOperation
接口,它会令人惊讶地编译:
class MyClass<T, U>
where T : Something
where U : IAnOperation<Something>
{
public U GetAnOperationOfSomething()
{
IAnOperation<T> anOperation = GenAnOperation();
return (U)anOperation;
}
private IAnOperation<T> GenAnOperation()
{
throw new NotImplementedException();
}
}
public class Something
{ }
public interface IAnOperation<T>
where T : Something
{ }
答案 4 :(得分:1)
目前还不清楚你要做什么,你可能想扩大这个问题。例如,会有几种类型的操作吗?根据具体情况,有几种可能的解决方案
如果没有操作子类型,则不需要U参数。只需返回document.querySelector('#inputImage').addEventListener('change', function() {
var reader = new FileReader();
reader.onload = function() {
var arrayBuffer = this.result,
array = new Uint8Array(arrayBuffer);
// Replace the subscriptionKey string value with your valid subscription key.
var subscriptionKey = "YOUR-KEY-HERE";
var uriBase = "https://YOUR-LOCATION-HERE.api.cognitive.microsoft.com/vision/v1.0/RecognizeText";
var params = {
"handwriting": "true",
};
$.ajax({
url: uriBase + "?" + $.param(params),
beforeSend: function(jqXHR) {
jqXHR.setRequestHeader("Content-Type", "application/octet-stream");
jqXHR.setRequestHeader("Ocp-Apim-Subscription-Key", subscriptionKey);
},
type: "POST",
processData: false,
data: arrayBuffer
})
.done(function(data, textStatus, jqXHR) {
// Show progress.
$("#responseTextArea").val("Handwritten text submitted. Waiting 10 seconds to retrieve the recognized text.");
setTimeout(function() {
// The "Operation-Location" in the response contains the URI to retrieve the recognized text.
var operationLocation = jqXHR.getResponseHeader("Operation-Location");
$.ajax({
url: operationLocation,
beforeSend: function(jqXHR) {
jqXHR.setRequestHeader("Content-Type", "application/json");
jqXHR.setRequestHeader("Ocp-Apim-Subscription-Key", subscriptionKey);
},
type: "GET",
})
.done(function(data) {
// Show formatted JSON on webpage.
$("#responseTextArea").val(JSON.stringify(data, null, 2));
})
.fail(function(jqXHR, textStatus, errorThrown) {
// Display error message.
var errorString = (errorThrown === "") ? "Error. " : errorThrown + " (" + jqXHR.status + "): ";
errorString += (jqXHR.responseText === "") ? "" : (jQuery.parseJSON(jqXHR.responseText).message) ?
jQuery.parseJSON(jqXHR.responseText).message : jQuery.parseJSON(jqXHR.responseText).error.message;
alert(errorString);
});
}, 10000);
})
.fail(function(jqXHR, textStatus, errorThrown) {
// Put the JSON description into the text area.
$("#responseTextArea").val(JSON.stringify(jqXHR, null, 2));
// Display error message.
var errorString = (errorThrown === "") ? "Error. " : errorThrown + " (" + jqXHR.status + "): ";
errorString += (jqXHR.responseText === "") ? "" : (jQuery.parseJSON(jqXHR.responseText).message) ?
jQuery.parseJSON(jqXHR.responseText).message : jQuery.parseJSON(jqXHR.responseText).error.message;
alert(errorString);
})
}
reader.readAsArrayBuffer(this.files[0]);
}, false);
,因为它已经可以描述所有操作。
AnOperation<T>
如果有多种操作(似乎很可能),那么问题是你的班级在不知道它们时不知道如何制作它们。您需要为您的类提供一个可以生成 // With only one type of operation
namespace ConsoleApp2
{
class MyClass<T> where T : Something
{
public AnOperation<T> GetAnOperationOfSomething()
{
AnOperation<T> anOperation = new AnOperation<T>();
return anOperation;
}
}
public class Something
{
}
public sealed class AnOperation<T>
where T : Something
{
}
}
实例的函数。
U
或者,您可以将 // With a factory for operations
namespace ConsoleApp1
{
class MyClass<T, U>
where T : Something
where U : AnOperation<Something>
{
private readonly Func<T, U> operationMaker;
public MyClass(Func<T, U> operationMaker)
{
this.operationMaker = operationMaker;
}
public U GetAnOperationOfSomething(T something)
{
U anOperation = operationMaker(something);
return anOperation;
}
}
public class Something
{
}
public class AnOperation<T>
where T : Something
{
}
}
限制为新U
,以便您的班级可以在不知情的情况下创建它们。
new()
答案 5 :(得分:0)
以下对我有用(编辑:我在框架v4.5.2中):
class Program
{
static void Main(string[] args)
{
MyClass<Something, AnOperation<Something>> obj = new MyClass<Something, AnOperation<Something>>();
}
}
class MyClass<T, U>
where T : Something
where U : AnOperation<Something>
{
public U GetAnOperationOfSomething()
{
AnOperation<T> anOperation = new AnOperation<T>();
return anOperation as U;
}
}
public class Something
{
}
public class AnOperation<T>
where T : Something
{
}