我有一个包含两种不同类型属性的模型类 - SourceData
,DestinationData
。这些属性包含类似类的实例(在不同的命名空间中),我需要手动比较并显示差异。
我想为这个问题创建通用扩展方法IsSame
,所以我可以简单地写一下:
// SourceData: x => ..., DestinatinData: y => ...
var nameIsSame = model.IsSame(x => x.Name, y => y.Name);
var ageIsSame = model.IsSame(x => x.Age, y => y.Age);
...
我准备了这个场景的样本,但我不能编写可以像上面那样调用的方法IsSame
。我必须为泛型方法调用指定所有类型。
public interface ISource
{ }
public interface IDestination
{ }
public class SourcePerson : ISource
{
public string Name { get; set; }
public int Age { get; set; }
}
public class DestinationPerson : IDestination
{
public string Name { get; set; }
public int Age { get; set; }
}
public abstract class DetailViewModel<TSource, TDestination>
where TSource : ISource
where TDestination : IDestination
{
public TSource SourceData { get; set; }
public TDestination DestinationData { get; set; }
}
public class PersonDetailViewModel : DetailViewModel<SourcePerson, DestinationPerson>
{ }
现在我有类型PersonDetailViewModel
的模型类,它实现了抽象类DetailViewModel<>
。我认为应该简单地通过提供可能因约束而被识别的ExtensionMethods.IsSame
实例来调用方法PersonDetailViewModel
的实现。
public static class ExtensionMethods
{
public static bool IsSame<TModel, TSource, TDestination, TValue>(this TModel model, Func<TSource, TValue> sourceProperty, Func<TDestination, TValue> destinationProperty)
where TModel : DetailViewModel<TSource, TDestination>
where TSource : ISource
where TDestination : IDestination
{
if (model.SourceData == null) {
return (model.DestinationData == null);
}
if (model.DestinationData == null)
return false;
return Equals(sourceProperty(model.SourceData), destinationProperty(model.DestinationData));
}
}
然而,当我尝试调用扩展方法时,我必须指定所有类型,即使编译器应该知道所有类型。
class Program
{
static void Main(string[] args)
{
var model = new PersonDetailViewModel
{
SourceData = new SourcePerson { Name = "Karel Gott", Age = 72 },
DestinationData = new DestinationPerson { Name = "Karel Engles", Age = 72 }
};
Console.WriteLine(model);
Console.WriteLine();
//var nameIsSame = model.IsSame(x => x.Name, y => y.Name); // doesn't work :-(
var nameIsSame = model.IsSame<PersonDetailViewModel, SourcePerson, DestinationPerson, string>(x => x.Name, y => y.Name);
Console.WriteLine("Name is same: " + nameIsSame);
//var ageIsSame = model.IsSame(x => x.Age, y => y.Age); // doesn't work :-(
var ageIsSame = model.IsSame<PersonDetailViewModel, SourcePerson, DestinationPerson, int>(x => x.Age, y => y.Age);
Console.WriteLine("Age is same: " + ageIsSame);
Console.WriteLine();
Console.WriteLine("Press any key to exit ...");
Console.ReadKey(true);
}
}
关于所有人的通知:请不要写信给我,我应该区别对待。我在这里使用方法IsSame只是为了简单。该方法运行良好,内部代码应该做其他事情。我只需要在没有明确定义类型的情况下调用它。在我看来,编译器应该从约束中了解它们。
在这种情况下,我使用了类PersonDetailViewModel,SourcePerson,DestinationPerson ......但在我的应用程序中有很多这样的类。 TSource和TDestination里面没有相同的代码,属性应该有不同的名称。想象一下,我想比较这些类中的属性:
public class SourceCompany : ISource {
public int CompanyId { get; set; }
public string NameTradeRegister { get; set; }
public string AddressStreet { get; set; }
public string Town { get; set; }
}
public class DestinationCompany : IDestination {
public int ID { get; set; }
public string Name { get; set; }
public string StreetName { get; set; }
public string City { get; set; }
}
var idIsSame = model.IsSame(x => CompanyId, y => y.ID);
好的,我找到了解决方案。扩展方法应该避免使用TModel,而是可以声明DetailViewModel。
public static class ExtensionMethods
{
public static bool IsSame<TSource, TDestination, TValue>(this DetailViewModel<TSource, TDestination> model, Func<TSource, TValue> sourceProperty, Func<TDestination, TValue> destinationProperty)
where TSource : ISource
where TDestination : IDestination
{
if (model.SourceData == null) {
return (model.DestinationData == null);
}
if (model.DestinationData == null)
return false;
return Equals(sourceProperty(model.SourceData), destinationProperty(model.DestinationData));
}
}