Tamam, tam olarak ne net değil IMapperonun içinde var ama başka kısıtlamalar nedeniyle mümkün olmayabilir, bazıları bir kaç şey önermek istiyorum. Bunu düşündüm ettik ben hemen hemen bu dışarı yazdım - Bunu daha kolay aynı şeyi bir dahaki sefere yapmak için yapacağız gibi, eylem düşünce dizisi görmeye yardımcı düşünüyorum. (Tabii, benim çözüm gibi varsayarsak :)
LINQ tarzında doğal olarak işlevseldir. Yani ideal olarak, sorgular yan etkilere sahip olmaması gerektiğini ifade eder. Örneğin, bir imza ile bir yöntemi beklediğiniz:
public IEnumerable<User> MapFrom(IEnumerable<User> users)
yerine mevcut kullanıcıları mutasyona daha, ekstra bilgiler içeren kullanıcı nesnelerinin yeni dizisi dönmek için. Şu anda ekliyorsanız tek bilgi avatar, o yüzden de bir yöntem eklersiniz Userçizgisinde:
public User WithAvatar(Image avatar)
{
// Whatever you need to create a clone of this user
User clone = new User(this.Name, this.Age, etc);
clone.FacebookAvatar = avatar;
return clone;
}
Hatta yapmak isteyebilirsiniz Usertamamen değişmez - Böyle oluşturucu deseni olarak o etrafında çeşitli stratejiler vardır. Daha fazla ayrıntı istiyorsanız sor. Neyse, önemli olan biz eskisinin kopyası olan yeni bir kullanıcı oluşturulur, ancak belirtilen avatarınızla olduğun.
İlk denemesi: iç birleşim
Şimdi geri Eşleştiricisi ... şu anda üç var kamu yöntemleri ama benim tahminim sadece ilki kamu olması gerektiğini ve API geri kalanı aslında Facebook kullanıcılarını maruz gerek olmamasıdır. Senin gibi görünüyor GetFacebookUsersyöntem temelde tamam ben muhtemelen boşluk açısından sorgu sıraya ediyorum rağmen.
Yani, yerel kullanıcılar bir dizi ve Facebook kullanıcılarının bir koleksiyon göz önüne alındığında, biz gerçek haritalama biraz yapıyor sol ediyoruz. Bir eşleştirme Facebook kullanıcısı olmayan yerel kullanıcıların vermez çünkü düz "katılmak" şartı, problemlidir. Bunun yerine, onlar bir avatar olmadan bir Facebook kullanıcı sanki olmayan bir Facebook kullanıcısı tedavi bazı yol gerekir. Esas olarak, bu boş nesne desenidir.
Biz boş uid sahip bir Facebook kullanıcısı ile gelerek bunu yapabilir (nesne modelini varsayarak olduğunu verir):
// Adjust for however the user should actually be constructed.
private static readonly FacebookUser NullFacebookUser = new FacebookUser(null);
Ancak, biz aslında bir istiyoruz dizisi bu ne çünkü bu kullanıcıların Enumerable.Concatkullanır:
private static readonly IEnumerable<FacebookUser> NullFacebookUsers =
Enumerable.Repeat(new FacebookUser(null), 1);
Şimdi biz sadece bizim gerçek birine bu kukla girdi "add" ve normal bir iç birleşim yapabilirsiniz. Bu unutmayın varsayar Facebook kullanıcı arama daima herhangi bir "gerçek" Facebook UID için bir kullanıcıyı bulacaktır. Eğer durum değilse, bu tekrar ve bir iç birleşim kullanmayın gerekirdi.
Sonra katılmak ve proje kullanarak bunu, sonunda "sıfır" kullanıcı şunlardır WithAvatar:
public IEnumerable<User> MapFrom(IEnumerable<User> users)
{
var facebookUsers = GetFacebookUsers(users).Concat(NullFacebookUsers);
return from user in users
join facebookUser in facebookUsers on
user.FacebookUid equals facebookUser.uid
select user.WithAvatar(facebookUser.Avatar);
}
Yani tam sınıf olacaktır:
public sealed class FacebookMapper : IMapper
{
private static readonly IEnumerable<FacebookUser> NullFacebookUsers =
Enumerable.Repeat(new FacebookUser(null), 1);
public IEnumerable<User> MapFrom(IEnumerable<User> users)
{
var facebookUsers = GetFacebookUsers(users).Concat(NullFacebookUsers);
return from user in users
join facebookUser in facebookUsers on
user.FacebookUid equals facebookUser.uid
select user.WithAvatar(facebookUser.pic_square);
}
private Facebook.user[] GetFacebookUsers(IEnumerable<User> users)
{
var uids = (from u in users
where u.FacebookUid != null
select u.FacebookUid.Value).ToList();
// return facebook users for uids using WCF
}
}
Burada birkaç nokta:
- önce belirtildiği gibi, iç bir kullanıcının Facebook UID geçerli bir kullanıcı olarak getirilen olmayabilir eğer sorunlu hale katılmak.
- yinelenen Facebook kullanıcı varsa Benzer sorunlarımız olsun - her yerel kullanıcı iki kez çıkan sona ereceğini!
- Bu sigara Facebook kullanıcıları için avatar (silen) yerini alır.
İkinci bir yaklaşım: grup katılması
Biz bu noktaları ele alabilir Bakalım. Bence getirilen ettik eğer farz edeceğiz birden tek bir Facebook UID için Facebook kullanıcılarını, o zaman biz dan avatar yakala bunlardan hangisinin önemi yoktur - onlar aynı olmalıdır.
İhtiyacımız her yerel kullanıcı için biz Facebook kullanıcıları eşleşen bir dizi olsun, böylece bir grup, katılmak olduğunu. Sonra kullanacağız DefaultIfEmptyhayatı kolaylaştırmak için.
Biz tutabilir WithAvatareskisi gibi - ama bu sefer biz sadece gelen avatar kapmak için bir Facebook kullanıcısı var eğer bunu arayacağız. Bir grup tarafından temsil edilmektedir C # sorgu ifadeleri katılmak join ... into. Bu sorgu makul uzun, ama dürüst, çok korkutucu değil!
public IEnumerable<User> MapFrom(IEnumerable<User> users)
{
var facebookUsers = GetFacebookUsers(users);
return from user in users
join facebookUser in facebookUsers on
user.FacebookUid equals facebookUser.uid
into matchingUsers
let firstMatch = matchingUsers.DefaultIfEmpty().First()
select firstMatch == null ? user : user.WithAvatar(firstMatch.pic_square);
}
İşte sorgu ifadesi yine, ama yorumlarla:
// "Source" sequence is just our local users
from user in users
// Perform a group join - the "matchingUsers" range variable will
// now be a sequence of FacebookUsers with the right UID. This could be empty.
join facebookUser in facebookUsers on
user.FacebookUid equals facebookUser.uid
into matchingUsers
// Convert an empty sequence into a single null entry, and then take the first
// element - i.e. the first matching FacebookUser or null
let firstMatch = matchingUsers.DefaultIfEmpty().First()
// If we've not got a match, return the original user.
// Otherwise return a new copy with the appropriate avatar
select firstMatch == null ? user : user.WithAvatar(firstMatch.pic_square);
olmayan LINQ çözeltisi
Başka bir seçenek olarak sadece biraz LINQ kullanmaktır. Örneğin:
public IEnumerable<User> MapFrom(IEnumerable<User> users)
{
var facebookUsers = GetFacebookUsers(users);
var uidDictionary = facebookUsers.ToDictionary(fb => fb.uid);
foreach (var user in users)
{
FacebookUser fb;
if (uidDictionary.TryGetValue(user.FacebookUid, out fb)
{
yield return user.WithAvatar(fb.pic_square);
}
else
{
yield return user;
}
}
}
Bu, bir yineleyici blok yerine LINQ sorgu ifade kullanır. ToDictionaryiki kez aynı anahtarı alırsa bir istisna durumu - Bu sorunu gidermek için bir seçenek değiştirmektir GetFacebookUsersemin sadece farklı kimlikleri arar hale getirmek için:
private Facebook.user[] GetFacebookUsers(IEnumerable<User> users)
{
var uids = (from u in users
where u.FacebookUid != null
select u.FacebookUid.Value).Distinct().ToList();
// return facebook users for uids using WCF
}
Bu web hizmeti elbette uygun şekilde çalışır varsayar - ama öyle değil, muhtemelen yine bir özel durum istiyoruz :)
Sonuç
Üç takım tercihinizi yapın. Grup katılmak anlamak muhtemelen en zor, ama en iyi davranır. Yineleyici blok çözeltisi muhtemelen en basit ve uyar davranması gerektiğini GetFacebookUsersmodifikasyonu.
Yapımı Userdeğişmez neredeyse kesin olsa olumlu bir adım olacaktır.
yan ürün Bu çözümlerin her biri güzel O kadar da iyi sizin için önemli olmayabilir. kullanıcılar içeri girdiler aynı sırada çıkıp yani, ama güzel bir özellik olabilir.
Umarım bu yardımcı olur - bu ilginç bir soru oldu :)
DÜZENLEME: mutasyon gitmek için yolu var mı?
Yerel Kullanıcı tipi aslında varlık çerçevesinde bir varlık türü olduğunu yorumlarınızda gördükten, o olabilir eylem bu kursu almak uygun olmayabilir. Iletmenin yapma hemen hemen söz konusu değildir, ben tip birçok kullanımı olacağını sanıyorum bekliyoruz mutasyonu.
Eğer durum buysa, daha açık olmasını sağlamak için olabildiğince arayüzünü değiştirmeye değer olabilir. Bunun yerine bir dönüş IEnumerable<User>(- bir ölçüde - ima hangi projeksiyon) böyle bir şey ile ayrılırken, sen imza ve isim hem değiştirmek isteyebilirsiniz:
public sealed class FacebookMerger : IUserMerger
{
public void MergeInformation(IEnumerable<User> users)
{
var facebookUsers = GetFacebookUsers(users);
var uidDictionary = facebookUsers.ToDictionary(fb => fb.uid);
foreach (var user in users)
{
FacebookUser fb;
if (uidDictionary.TryGetValue(user.FacebookUid, out fb)
{
user.Avatar = fb.pic_square;
}
}
}
private Facebook.user[] GetFacebookUsers(IEnumerable<User> users)
{
var uids = (from u in users
where u.FacebookUid != null
select u.FacebookUid.Value).Distinct().ToList();
// return facebook users for uids using WCF
}
}
; Ama sen gerçekten "sorgulama" konum olarak o, makul - Yine, bu (ana operasyonda) özellikle "LINQ-y" çözüm artık değil Eğer "güncelleme" ediyoruz.