この状況には2つの解決策があります。
最初の解決策
既に与えられているExcepWith
a 内のすべてのアイテムを削除できるメソッドを作成できます。このようなメソッドのコードは次のとおりです。ICollection<T>
IEnumerable<T>
public static int ExceptWith<TItem>
(
this ICollection<TItem> collection,
IEnumerable<TItem> other
)
{
if (ReferenceEquals(collection, null))
{
throw new ArgumentNullException("collection");
}
else if (ReferenceEquals(other, null))
{
throw new ArgumentNullException("other");
}
else
{
int count = 0;
foreach (var item in other)
{
while (collection.Remove(item))
{
count++;
}
}
return count;
}
}
これstring[]
で、ユーザーの入力が得られました。その配列は anIEnumerable<string>
ではなくICollection<string>
... であり、次のように簡単に解決できます。
これの代わりに:
string[] AttributeTags =
txtAttributeTags.Text.Split
(
new string[] { "," },
StringSplitOptions.RemoveEmptyEntries
);
これをして:
var AttributeTags =
new List<string>
(
txtAttributeTags.Text.Split
(
new string[] { "," },
StringSplitOptions.RemoveEmptyEntries
)
);
またはこれでも:
var AttributeTags =
txtAttributeTags.Text.Split
(
new string[] { "," },
StringSplitOptions.RemoveEmptyEntries
).ToList();
今、あなたはこれを行うことができます:
AttriuteTags.ExceptWith(existingTags);
attribute.AttributeTag のタイプはIEnumerable<string>
Select を使用しないため:
AttriuteTags.ExceptWith(attribute.AttributeTag.Select(item => item.value));
これにより、新しいタグのみがリストに残ります。
注: このメソッドは、Remove の実装に依存します。特別な比較を行う必要がある場合は、このメソッドではうまくいきません。
2 番目のソリューション
別の方法があります。クラスからの例外を使用できます。Enumerable
string[] AttributeTags =
txtAttributeTags.Text.Split
(
new string[] { "," },
StringSplitOptions.RemoveEmptyEntries
);
var newTags = AttributeTags.Except(existingTags);
attribute.AttributeTag のタイプはIEnumerable<string>
Select を使用しないため:
string[] AttributeTags =
txtAttributeTags.Text.Split
(
new string[] { "," },
StringSplitOptions.RemoveEmptyEntries
);
var newTags = AttributeTags.Except
(
attribute.AttributeTag.Select(item => item.value)
);
これにより、newTags、つまり新しいタグが挿入されます。
注: 特別な比較を行う必要がある場合は、メソッドの他のオーバーロードを使用する必要があります。
string[] AttributeTags =
txtAttributeTags.Text.Split
(
new string[] { "," },
StringSplitOptions.RemoveEmptyEntries
);
var newTags = AttributeTags.Except(attribute.AttributeTag, equalityComparer);
悲しいことに、equalityComparer は IEqualityComparer を実装するクラスのオブジェクトです。つまり、そこでラムダを使用することはできません。そのために、このクラスを追加できます:
public class CustomEqualityComparer<T> : IEqualityComparer<T>
{
private Func<T, T, bool> _comparison;
private Func<T, int> _getHashCode;
public CustomEqualityComparer
(
Func<T, T, bool> comparison,
Func<T, int> getHashCode
)
{
if (ReferenceEquals(comparison, null))
{
throw new ArgumentNullException("comparison");
}
else if (ReferenceEquals(getHashCode, null))
{
throw new ArgumentNullException("getHashCode");
}
else
{
_comparison = comparison;
_getHashCode = getHashCode;
}
}
public bool Equals(T x, T y)
{
return _comparison.Invoke(x, y);
}
public int GetHashCode(T obj)
{
return _getHashCode.Invoke(obj);
}
}
そして、次のように呼び出します (例):
string[] AttributeTags =
txtAttributeTags.Text.Split
(
new string[] { "," },
StringSplitOptions.RemoveEmptyEntries
);
var newTags = AttributeTags.Except
(
existingTags,
new CustomEqualityComparer<string>
(
(a, b) => 1, //your custom comparison here
str => str.GetHashCode()
)
);
attribute.AttributeTag のタイプはIEnumerable<string>
Select を使用しないため:
string[] AttributeTags =
txtAttributeTags.Text.Split
(
new string[] { "," },
StringSplitOptions.RemoveEmptyEntries
);
var newTags = AttributeTags.Except
(
attribute.AttributeTag.Select(item => item.value),
new CustomEqualityComparer<string>
(
(a, b) => 1, //your custom comparison here
str => str.GetHashCode()
)
);
新しいタグの追加
新しいタグができたので、たとえば でnewTags
、それを繰り返して新しいタグを追加できます。
var now = DateTime.Now;
foreach (var item in newTags)
{
AttributeTag tag = new AttributeTag { value = item, timestamp = now };
attribute.AttributeTags.Add(tag);
}
ソリューションの比較
これらの方法の違いは何ですか?
- 1 つ目は必要なメモリが少ない
- 1 つ目は、新しいメソッドを定義する必要があります。
- 最初はカスタムを許可しません
IEqualityComparer<T>
- 2 つ目は遅延実行を可能にします。
- 2 つ目は (必要ではありませんが) ヘルパー クラスを使用します。