Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C#中模拟C#6空条件<;6._C#_C# 5.0_C# 6.0 - Fatal编程技术网

如何在C#中模拟C#6空条件<;6.

如何在C#中模拟C#6空条件<;6.,c#,c#-5.0,c#-6.0,C#,C# 5.0,C# 6.0,用C#6.0,我可以做到这一点 var isEqual = x.Id == y.Id && x.UpdatedAt == y.UpdatedAt && x.Name == y.Name && x.RulesUrl == y.RulesUrl && x.OngoingChall

用C#6.0,我可以做到这一点

var isEqual = x.Id == y.Id
              && x.UpdatedAt == y.UpdatedAt
              && x.Name == y.Name                        
              && x.RulesUrl == y.RulesUrl
              && x.OngoingChallenges?.Count == y.OngoingChallenges?.Count
              && x.MembershipIds?.Count == y.MembershipIds?.Count;
使用C#<6.0有什么好的解决方案吗

我是说这部分

&& x.OngoingChallenges?.Count == y.OngoingChallenges?.Count
&& x.MembershipIds?.Count == y.MembershipIds?.Count;

因为在旧项目中,我们不可能使用C#6.0。如何高效地编写isEqual?

在您将使用的C#version<6.0中

正如@Hamlet Hakobyan所指出的,这在语义上并不完全等同于使用
?。
的原始C#6.0解决方案,但您可以将其更改为(根据@hvd):

这取决于您是否想考虑一个缺失的集合和一个空集合是否相等。


您还可以使用并提供替换对象。假设对象是某种类型的列表:

var empty = new List<int>();
var isEqual = x.Id == y.Id
    && x.UpdatedAt == y.UpdatedAt
    && x.Name == y.Name                        
    && x.RulesUrl == y.RulesUrl
    && (x.OngoingChallenges ?? empty).Count == (y.OngoingChallenges ?? empty).Count
    && (x.MembershipIds ?? empty).Count == (y.MembershipIds ?? empty).Count;
var empty=新列表();
变量isEqual=x.Id==y.Id
&&x.UpdatedAt==y.UpdatedAt
&&x.Name==y.Name
&&x.RulesUrl==y.RulesUrl
&&(x.OngoingChallenges??空)。计数==(y.OngoingChallenges??空)。计数
&&(x.MembershipID??空)。计数==(y.MembershipID??空)。计数;

x.OnGoingChallenges?.Count
相当于
x.OnGoingChallenges!=无效的x、 Count:default(int?
(还有其他方法,但最后是一种称为空条件运算符的空检查快捷方式)

也就是说,在没有C#6的情况下,您的代码不能用语法优雅的语句重写,但您可以使用扩展方法模拟这个新的C#6特性

public static class StructExtensions
{
    // Check that TProperty is nullable for the return value (this is how C#6's
    // null-conditional operator works with value types
    public static TProperty? GetOrDefault<TObject, TProperty>(this TObject someObject, Func<TObject, TProperty> propertySelectionFunc)
        where TObject : class 
        where TProperty : struct
    {
        Contract.Requires(propertySelectionFunc != null);

        return someObject == null ? default(TProperty?) : propertySelectionFunc(someObject);
    }
}
整个扩展方法将用于获取值类型的属性值或其默认值。您可能会也可能不会扩展扩展方法类来支持获取引用类型值或null。

在C#6之前,我使用了类似的方法

 public static class CommonExtensions
 {
     public static TValue TryGet<TObject, TValue>(this TObject obj, Func<TObject, TValue> getter, TValue defaultValue = default(TValue))
         where TObject : class
     {
         return obj == null ? defaultValue : getter(obj);
     }

     //If objects types are equals
     public static bool KeyEquals<TObject, TValue>(this TObject a, TObject b, Func<TObject, TValue> keyGetter)
        where TObject : class
     {
         return a != null 
             && b != null 
             && EqualityComparer<TValue>.Default.Equals(keyGetter(a), keyGetter(b));
     }
 }



 var isEqual = x.Id == y.Id
               && x.UpdatedAt == y.UpdatedAt
               && x.Name == y.Name                        
               && x.RulesUrl == y.RulesUrl
               //v1
               && x.OngoingChallenges.TryGet(v => v.Count) == y.OngoingChallenges.TryGet(v => v.Count)
               //v2
               && x.MembershipIds.KeyEquals(y.MembershipIds, v => v.Count);
公共静态类公共扩展
{
公共静态TValue TryGet(这个TObject对象,Func getter,TValue defaultValue=default(TValue))
对象:班级
{
返回obj==null?默认值:getter(obj);
}
//如果对象类型等于
公共静态bool KeyEquals(此TObject a、TObject b、Func keyGetter)
对象:班级
{
返回一个!=null
&&b!=null
&&EqualityComparer.Default.Equals(keyGetter(a),keyGetter(b));
}
}
变量isEqual=x.Id==y.Id
&&x.UpdatedAt==y.UpdatedAt
&&x.Name==y.Name
&&x.RulesUrl==y.RulesUrl
//v1
&&x.OngoingChallenges.TryGet(v=>v.Count)==y.OngoingChallenges.TryGet(v=>v.Count)
//v2
&&x.membershipId.KeyEquals(y.membershipId,v=>v.Count);

那么您的解决方案是什么?@senzacionale,例如三元运算符:
(x.MembershipId==null?(int?)null:x.MembershipId.Count)
“因为在旧项目中,我们不可能使用C#6.0”。为什么不呢?如果你有Visual Studio 2015,你可以针对较旧的.NET运行时,但仍然使用新的C#6编译器和语法。编译后的IL代码与更详细的旧语法没有区别。您的第一个解决方案存在问题。它假设
null等于0
,这是错误的假设。如果每次读取属性时都构造一个新列表(或返回任何类型),那么在性能方面,两次读取
OngoingChallenges
属性可能是一个问题。如果它是一个只读列表,但它的目标是一个没有
ReadOnlyCollection
的框架版本,那么这可能是它每次都会返回一个新列表的一个很好的原因。第二个选项为
,很好地避免了这个问题。(吹毛求疵:你不会把
a==b
称为“你会使用一个二进制表达式”,你会直截了当地提到等式运算符。
?:
被称为条件运算符。)@HamletHakobyan的观点也是公平的。通过将
0
更改为
default(int?
/
(int?)null
可以很容易地解决这个问题。我认为使用
default(int?
(int?)null
的解决方案与原始C#6.0解决方案最匹配。但根据情况,将缺少的集合和空集合视为相等仍然可以接受。
?:
不要求第二个和第三个操作数具有相同的类型。它只需要一种类型可以转换为另一种类型<代码>x.MembershipId==null:null?x、 MembershipIds.Count不会编译,因为
null
没有
int
可以转换的类型,并且
null
不能转换为
int
。但是,
x.membershipId==null:default(int?)?x、 MembershipId.Count将被编译,因为第二个操作数的类型为
int?
,而类型为
int
的第三个操作数可以隐式转换为
int?
。你对我的评论是哈姆雷特·哈科比安的。:)
someObject.Equals(默认值(TProperty))
看起来不正确。除了抛出
NullReferenceException
之外,如果
someObject
null
,您应该将其与
default(TObject)
进行比较,而不是
default(TProperty)
。由于您需要
TObject:class
,您知道
默认值(TObject)
null
,在这一点上,您可以简单地编写
someObject==null
。这是一个很好的主意,但我有一个错误:不包含“OngoingChallenges”的定义…@senzacionale除了
GetOrDefault
定义本身是错误的之外,示例用法也有问题。它应该是
x.OngoingChallenges.GetOrDefault(c=>c.Count)
,而不是
x.OngoingChallenges.GetOrDefault(c=>c.OngoingChallenges.Count)
。其他用途相同。:)这应该可以解释你看到的错误。@hvd是的,你在所有问题上都是对的。我已经修好了,谢谢。我正在改进样本,但忘记了r
public static class StructExtensions
{
    // Check that TProperty is nullable for the return value (this is how C#6's
    // null-conditional operator works with value types
    public static TProperty? GetOrDefault<TObject, TProperty>(this TObject someObject, Func<TObject, TProperty> propertySelectionFunc)
        where TObject : class 
        where TProperty : struct
    {
        Contract.Requires(propertySelectionFunc != null);

        return someObject == null ? default(TProperty?) : propertySelectionFunc(someObject);
    }
}
var isEqual = x.Id == y.Id
                          && x.UpdatedAt == y.UpdatedAt
                          && x.Name == y.Name                        
                          && x.RulesUrl == y.RulesUrl
                          && x.OngoingChallenges.GetOrDefault(c => c.Count) == y.OngoingChallenges.GetOrDefault(c => c.Count)
                          && x.MembershipIds.GetOrDefault(m => m.Count) == x.MembershipIds.GetOrDefault(m => m.Count);
 public static class CommonExtensions
 {
     public static TValue TryGet<TObject, TValue>(this TObject obj, Func<TObject, TValue> getter, TValue defaultValue = default(TValue))
         where TObject : class
     {
         return obj == null ? defaultValue : getter(obj);
     }

     //If objects types are equals
     public static bool KeyEquals<TObject, TValue>(this TObject a, TObject b, Func<TObject, TValue> keyGetter)
        where TObject : class
     {
         return a != null 
             && b != null 
             && EqualityComparer<TValue>.Default.Equals(keyGetter(a), keyGetter(b));
     }
 }



 var isEqual = x.Id == y.Id
               && x.UpdatedAt == y.UpdatedAt
               && x.Name == y.Name                        
               && x.RulesUrl == y.RulesUrl
               //v1
               && x.OngoingChallenges.TryGet(v => v.Count) == y.OngoingChallenges.TryGet(v => v.Count)
               //v2
               && x.MembershipIds.KeyEquals(y.MembershipIds, v => v.Count);