在强制转换两个相同对象时无法强制转换对象



在我的模型中,我有三个相同的类(视图,UViews, TotalConfiguration和StatsViewModel)。它们都有相同的属性:

public class Views
{
public int idProject {get;set;}
public int January { get; set; }
public int February { get; set; }
public int March { get; set; }
public int April { get; set; }
public int May { get; set; }
public int June { get; set; }
public int July { get; set; }
public int August { get; set; }
public int September { get; set; }
public int October { get; set; }
public int November { get; set; }
public int December { get; set; }
}

我想通过上下文从数据库(从视图或UViews或TotalConfiguration)获取数据,并将结果保存到列表类型StatsViewModel:

//some code
var customer = _context.Get<UViews>(x => x.Projects.ProjectsUser.Where(x => x.IdUser == userId).Any());
//some code
public StatsViewModel Get<T>(Expression<Func<T, bool>> predicate)
where T : class
{
List<StatsViewModel> listItem = new List<StatsViewModel>();
StatsViewModel item = new StatsViewModel();
var listFromDatabase = Set<T>().Where(predicate).ToList();
listItem.AddRange(listFromDatabase.Cast<StatsViewModel>());
item = listItem.FirstOrDefault();
return item;
}

代码工作完美行listItem.AddRange(listFromDatabase.Cast<StatsViewModel>());。当我尝试转换listFromDatabase列到I got error:

System.InvalidCastException: 'Unable to cast object 
of type 'Housematica.Data.Data.CMS.Statistics.UViews' 
to type 'Housematica.Intranet.ViewModel.StatsViewModel'.'

我试着这样做,但在这种情况下,我得到了同样的错误:

var listFromDatabase = Set<T>().Where(predicate).ToList().Cast<StatsViewModel>();

从编译器的角度来看,这些类型没有任何内容共同之处。仅仅因为两个类型具有相同的属性并不能使它们成为相同的类型。当类通常也有方法时,这变得更加清楚。. 如何指明两个类具有相同的方法?想象这两个:

class ClassA
{
int MyProperty { get; set; }
void DoSomething() => { Console.WriteLine(MyProperty); }
}
class ClassB
{
int MyProperty { get; set; }
void DoSomething() => { Console.WriteLine("Hello world"); }
}

上述两个类是否相等,因为它们具有相同的成员?很难说。当然它们的属性是匹配的,但是它们的方法呢?这两个相等吗?嗯,从正式的角度来看,只要考虑到他们的签名,人们就会认为是这样。然而,他们做的事情完全不同。因此,编译器不可能假设您的两种类型是否实际上表示相同的东西,这就是为什么它不(隐式地)允许这样的转换。

但是你还有很多其他的机会。最简单的方法是创建一些映射函数:

ClassA Map(ClassB b) => new ClassA { MyProperty = b.MyProperty };

现在你可以这样调用它:

myList.Select(x => Map(x));
另一种方法是复制构造函数:
class ClassA
{
public ClassA(ClassB b) { this.MyProerty = b.MyProperty }
}

可以用Select-语句调用:

myList.Select(x => new ClassA(x));

最后,您可以引入一些隐式或显式转换:

static explicit operator ClassA(ClassB b) => new ClassA { MyProperty = b.MyProperty };

,这是唯一可以用于强制转换的:

myList.Select(x => (ClassA)x);

但是要注意,从IEnumerable<T>调用泛型Cast<T>不会反映用户定义的强制转换。因此,下面的代码仍然不能用于上述三种解决方案中的任何一种:

myList.Cast<ClassA>();

最后我找到了类似JsonConvert的东西,我在我的代码中使用它:

public StatsViewModel Get<T>(Expression<Func<T, bool>> predicate) where T : class
{
StatsViewModel item = new StatsViewModel();
var listFromDatabase = Set<T>().Where(predicate).ToList();

List<StatsViewModel> targetlst = JsonConvert.DeserializeObject<List<StatsViewModel>>
(JsonConvert.SerializeObject(listFromDatabase));
item = targetlst.FirstOrDefault();
return item;
}

最新更新