无法将匿名类型#1[]隐式转换为匿名类型#2[]。

3
我有以下情景:
public JsonResult ChangeFilterList(int option)
{
    var data = new[] { new { Text = "Unknown option", Value = -1 } };
    switch (option)
    {
        case 2: data = _departmentnameRepository.All.Select(x => new { Text = x.DeptName, Value = x.Id }).ToArray();
            break;
        case 3: data = Session["projectid"] == null
                ? _assetSequenceRepository.All.Select(x => new { Text = x.AssetShotName, Value = x.Id }).ToArray()
                : _assetSequenceRepository.FindBy(p => p.ProjectId == (int)Session["projectid"]).Select(x => new { Text = x.AssetShotName, Value = x.Id }).ToArray();
            break;
        default: data = _userRepository.All.Select(x => new { Text = x.DisplayName, Value = x.UserID }).ToArray();
            break;
    }            

    return Json(data, JsonRequestBehavior.AllowGet);
}

case2default看起来很好,但在第3个条件语句中抱怨说:Cannot implicitly convert type 'AnonymousType#1[]' to 'AnonymousType#2[]'。既然我已经提供了匿名类型的蓝图作为var data = new[] { new { Text = "Unknown option", Value = -1 } };,那么?:不应该能够决定类型吗?

解决方案:

@Darin Dimitrov的答案很好,但我想对匿名类型进行一些测试(简单情况总是需要的)。 正如@Douglas所怀疑的那样:我的assetSequenceRepository正在提供id作为long,而匿名Value更倾向于int而不是long。由于C#编译器不会隐式地将long转换为int,所以我得到了错误。编译片段如下:

public JsonResult ChangeFilterList(int option = 3)
        {
            var data = new[] { new { Text = "Unknown option", Value = long.MaxValue } };
            switch (option)
            {
                case 2: data = _departmentnameRepository.All.Select(x => new { Text = x.DeptName, Value = (long)x.Id }).ToArray();
                    break;
                case 3: data = Session["projectid"] == null
                        ? _assetSequenceRepository.All.Select(x => new { Text = x.AssetShotName, Value = x.Id }).ToArray()
                        : _assetSequenceRepository.FindBy(p => p.ProjectId == (int)Session["projectid"]).Select(x => new { Text = x.AssetShotName, Value = x.Id }).ToArray();
                    break;
                default: data = _userRepository.All.Select(x => new { Text = x.DisplayName, Value = (long)x.UserID }).ToArray();
                    break;
            }            

            return Json(data, JsonRequestBehavior.AllowGet);
        }

一个简单的解决方法是将你的 ?: 语句替换为一个 if...else 块。 - Douglas
我尝试了但是效果一样,不知道哪里出了问题。 - Bishnu Rawal
你在使用 if...else 时遇到了什么错误信息?这个错误是在 if 赋值、else 赋值还是两者都有? - Douglas
@BishnuRawal 注意,在switch块中将被丢弃,因此将数据初始化为new[] { new { Text = "Unknown option", Value = -1 } }是不必要的。 - Ahmed KRAIEM
@Douglas:ifelse块都出现了相同的错误。 - Bishnu Rawal
如果我不这样做,而是写var data;或者var data = null,编译器会抱怨:将某些东西分配给隐式变量data并且不能将null分配给data - Bishnu Rawal
3个回答

5
你正在对编译器进行真正的测试。只需编写一个视图模型来结束它的痛苦并使事情更加明确:
public class MyViewModel
{
    public int Value { get; set; }
    public string Text { get; set; }
}

然后将您的LINQ查询投影到此视图模型中,以避免使用条件运算符和匿名类型可能引起的任何不明确性:

public ActionResult ChangeFilterList(int option)
{
    var data = new[] 
    { 
        new MyViewModel { Text = "Unknown option", Value = -1 } 
    };

    switch (option)
    {
        case 2: data = _departmentnameRepository
            .All
            .Select(x => new MyViewModel { Text = x.DeptName, Value = x.Id })
            .ToArray();
            break;
        case 3: data = Session["projectid"] == null
                ? _assetSequenceRepository
                    .All
                    .Select(x => new MyViewModel { Text = x.AssetShotName, Value = x.Id })
                    .ToArray()
                : _assetSequenceRepository
                    .FindBy(p => p.ProjectId == (int)Session["projectid"])
                    .Select(x => new MyViewModel { Text = x.AssetShotName, Value = x.Id })
                    .ToArray();
            break;
        default: data = _userRepository
            .All
            .Select(x => new MyViewModel { Text = x.DisplayName, Value = x.UserID })
            .ToArray();
            break;
    }            

    return Json(data, JsonRequestBehavior.AllowGet);
}

谢谢Darin,这是唯一的解决方法吗?我想过这个方法,但是思考微不足道的情况时,我最终选择了匿名。 - Bishnu Rawal

4
我猜测你的FindBy方法返回的对象属性类型与你期望的不同(例如,int?而不是int)。尝试指定类型转换以确保匿名类型具有正确的定义:
case 3: data = Session["projectid"] == null
             ? _assetSequenceRepository.All.Select(x => new { Text = x.AssetShotName, Value = x.Id }).ToArray()
             : _assetSequenceRepository.FindBy(p => p.ProjectId == (int)Session["projectid"]).Select(x => new { Text = (string)x.AssetShotName, Value = (int)x.Id }).ToArray();
        break;

关键变化是:
new { Text = (string)x.AssetShotName, Value = (int)x.Id })
                  ↖    explicit type casts    ↗

你是对的,assetSequenceRepository 返回的 id 是 long 类型,这是一个新手错误,现在它已经完美编译了。谢谢,我接受你的答案。 - Bishnu Rawal

0

以下测试代码可以成功编译:

public void Test(int option, string parameter)
{
    var data = new[] { new { Text = "Unknown option", Value = -1 } };

    switch(option)
    {
        case 2:
            data = Enumerable.Range(1, 4)
                             .Select(x => new { Text = x.ToString(), Value = x })
                             .ToArray();
            break;
        case 3:
            data = (new Random()).Next(2) % 2 == 1
                ? Enumerable.Range(1, 6)
                            .Select(x => new { Text = x.ToString(), Value = x })
                            .ToArray()
                : Enumerable.Range(1, 2)
                            .Select(x => new { Text = x.ToString(), Value = x })
                            .ToArray();
            break;
        default:
            data = Enumerable.Range(1, 3)
                             .Select(x => new { Text = x.ToString(), Value = x })
                             .ToArray();
            break;
    }
}

我只将您的存储库调用更改为Enumerable.Range()Select lambda,以获取正确的string/int属性值。

我猜想您展示的并不是您试图编译的代码。在您的实际代码中,可能存在一个名称不匹配(例如,大小写不正确)或类型不正确的属性。

您可以将鼠标指针悬停在ToArray()调用上,尝试弄清楚问题所在。工具提示中会打印出a is new { string Text, int Value }


Marin,我确定我的开发代码与每个情况中提供的{ Text = "未知选项", Value = -1 }是相同的。 - Bishnu Rawal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接