ठीक है, यह स्पष्ट नहीं है कि वास्तव में क्या IMapperउस में है, लेकिन मैं कुछ चीजें, जिनमें से कुछ अन्य प्रतिबंधों के कारण संभव नहीं हो सकता है सुझाव देना चाहेंगे। मैं बहुत ज्यादा यह पता लिखा है के रूप में मैं इसके बारे में सोचा है - मैं इसे कार्रवाई में सोच की धारा को देखने के लिए मदद करता है, के रूप में यह आसान आप एक ही बात अगली बार करने के लिए बनाती हूँ लगता है। (यह मानते हुए कि आप मेरे समाधान चाहते, ज़ाहिर है :)
LINQ शैली में स्वाभाविक कार्यात्मक है। इसका मतलब है कि आदर्श, प्रश्नों दुष्प्रभाव नहीं होना चाहिए। उदाहरण के लिए, मैं के हस्ताक्षर के साथ एक विधि उम्मीद थी:
public IEnumerable<User> MapFrom(IEnumerable<User> users)
बल्कि मौजूदा उपयोगकर्ताओं परिवर्तनशील से अतिरिक्त जानकारी के साथ उपयोगकर्ता वस्तुओं की एक नया अनुक्रम वापस जाने के लिए,। केवल जानकारी आप वर्तमान में जोड़ रहे हैं अवतार है, इसलिए मैं में एक विधि जोड़ना होगा Userकी तर्ज पर:
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;
}
तुम भी बनाने के लिए चाहते हो सकता है Userपूरी तरह से अडिग - जैसे बिल्डर पैटर्न के रूप में है कि चारों ओर विभिन्न रणनीतियों, देखते हैं। मुझे आप से पूछें कि आप अधिक विवरण चाहते हैं। वैसे भी, मुख्य बात यह है कि हम जो पुराने एक की एक प्रति है एक नया उपयोगकर्ता बना लिया है, लेकिन निर्दिष्ट अवतार के साथ है।
पहला प्रयास: भीतरी में शामिल होने के
अब वापस अपने नक्शाकार करने के लिए ... आप वर्तमान में तीन मिल गया है सार्वजनिक तरीकों लेकिन मेरे अनुमान है कि केवल पहले एक सार्वजनिक होना चाहिए, और एपीआई के बाकी वास्तव में फेसबुक उपयोगकर्ताओं को बेनकाब करने की जरूरत नहीं है कि है। ऐसा लगता है कि अपने GetFacebookUsersविधि मूल रूप से ठीक है, हालांकि मैं शायद खाली स्थान के के मामले में क्वेरी को पंक्तिबद्ध चाहते हैं।
तो, स्थानीय उपयोगकर्ताओं के अनुक्रम और फेसबुक उपयोगकर्ताओं का एक संग्रह को देखते हुए, हम वास्तविक मानचित्रण बिट कर जाते हैं। क्योंकि यह स्थानीय उपयोगकर्ताओं जो एक मिलान फेसबुक उपयोगकर्ता की जरूरत नहीं है उत्पन्न नहीं करेंगे एक सीधे "में शामिल होने" खंड, समस्याग्रस्त है। इसके बजाय, हम एक गैर Facebook उपयोगकर्ता के इलाज के रूप में यदि वे एक अवतार के बिना एक Facebook उपयोगकर्ता थे की किसी तरह की जरूरत है। अनिवार्य रूप से इस अशक्त वस्तु पैटर्न है।
हम ऐसा कर सकते हैं एक Facebook उपयोगकर्ता जो एक अशक्त uid है के साथ आ द्वारा (ऑब्जेक्ट मॉडल संभालने की अनुमति देता है कि):
// Adjust for however the user should actually be constructed.
private static readonly FacebookUser NullFacebookUser = new FacebookUser(null);
हालांकि, हम वास्तव में एक चाहते अनुक्रम , इन उपयोगकर्ताओं की वजह से वो क्या है Enumerable.Concatका उपयोग करता है:
private static readonly IEnumerable<FacebookUser> NullFacebookUsers =
Enumerable.Repeat(new FacebookUser(null), 1);
अब हम केवल हमारे असली को यह डमी प्रविष्टि "जोड़ें" कर सकते हैं, और एक सामान्य भीतरी में शामिल होने से करते हैं। नोट: यह है कि मान लिया गया है कि फेसबुक उपयोगकर्ताओं के देखने हमेशा किसी भी "असली" फेसबुक यूआईडी के लिए एक उपयोगकर्ता मिल जाएगा। अगर ऐसा नहीं है, हम इस पर दोबारा जाने और एक आंतरिक में शामिल होने का उपयोग नहीं करना होगा।
हम तो शामिल होते हैं और इस परियोजना का उपयोग कर, अंत में "अशक्त" उपयोगकर्ता शामिल 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);
}
तो पूर्ण वर्ग होगा:
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
}
}
यहाँ कुछ अंक:
- जैसा कि पहले बताया गया है, भीतरी में शामिल होने के समस्याग्रस्त हो जाता है यदि कोई उपयोगकर्ता के फेसबुक यूआईडी मान्य उपयोगकर्ता के रूप में प्राप्त नहीं किया जा सकता है।
- इसी तरह हम समस्याओं मिल अगर हम डुप्लीकेट फेसबुक उपयोगकर्ताओं है - प्रत्येक स्थानीय उपयोगकर्ता दो बार बाहर आ रहा अंत होगा!
- यह बदल देता है (को हटाता है) गैर फेसबुक उपयोगकर्ताओं के लिए अवतार।
एक दूसरा दृष्टिकोण: समूह में शामिल होने
देखते हैं कि हम इन बातों का समाधान कर सकते हैं या नहीं। मैं मान लेंगे कि अगर हम लाए जाने है कई एक भी फेसबुक यूआईडी के लिए फेसबुक उपयोगकर्ताओं है, तो यह कोई फर्क नहीं पड़ता जो उनमें से हम से अवतार हड़पने - वे एक ही होना चाहिए।
क्या हम की जरूरत है एक समूह में शामिल करें, ताकि प्रत्येक स्थानीय उपयोगकर्ता के लिए हम फेसबुक उपयोगकर्ताओं मिलान के एक दृश्य मिलता है। हम तो इस्तेमाल करेंगे DefaultIfEmptyजीवन को आसान बनाने के लिए।
हम रख सकते WithAvatarके रूप में यह पहले था - लेकिन इस बार हम केवल यह कॉल करने के लिए हम से अवतार हड़पने के लिए एक Facebook उपयोगकर्ता मिल गया है, तो जा रहे हैं। एक समूह का प्रतिनिधित्व करती है सी # क्वेरी भाव में शामिल होने के join ... into। इस क्वेरी यथोचित लंबा है, लेकिन यह बहुत डरावना नहीं, ईमानदार है!
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);
}
क्वेरी अभिव्यक्ति फिर से है, लेकिन टिप्पणी के साथ:
// "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);
गैर LINQ समाधान
एक अन्य विकल्प थोड़ा बहुत ही LINQ उपयोग करने के लिए है। उदाहरण के लिए:
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;
}
}
}
यह एक iterator ब्लॉक के बजाय एक LINQ क्वेरी अभिव्यक्ति का उपयोग करता है। ToDictionaryअगर यह एक ही कुंजी को दो बार प्राप्त करता है एक अपवाद फेंक होगा - यह आस-पास काम करने के लिए एक विकल्प बदलने के लिए है GetFacebookUsersयकीन है कि यह केवल अलग आईडी के लिए लग रहा है बनाने के लिए:
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
}
यही कारण है कि मान लिया गया है वेब सेवा उचित रूप से काम करता है, निश्चित रूप से - लेकिन अगर ऐसा नहीं होता है, तो आप शायद वैसे भी एक अपवाद फेंक करना चाहते हैं :)
निष्कर्ष
तीन में से अपने पसंद है। समूह में शामिल होने शायद समझने के लिए सबसे मुश्किल है, लेकिन सबसे अच्छा व्यवहार करता है। Iterator ब्लॉक समाधान संभवतः सबसे सरल है, और साथ ठीक से व्यवहार करना चाहिए GetFacebookUsersसंशोधन।
बनाना Userअपरिवर्तनीय लगभग निश्चित रूप से एक सकारात्मक कदम है, हालांकि होगा।
उप-उत्पाद के इन समाधानों में से सभी में से एक अच्छा है कि उपयोगकर्ताओं को एक ही आदेश है कि वे में चला गया में बाहर आ रहा है। यही कारण है कि अच्छी तरह से नहीं आप के लिए महत्वपूर्ण हो सकता है, लेकिन यह एक अच्छा संपत्ति हो सकती है।
आशा है कि इस मदद करता है - यह एक दिलचस्प सवाल हो गया है :)
संपादित करें: उत्परिवर्तन जाने का रास्ता है?
अपनी टिप्पणी में देखने के बाद कि स्थानीय उपयोगकर्ता प्रकार वास्तव में इकाई की रूपरेखा से एक इकाई प्रकार है, यह हो सकता है कार्रवाई के इस पाठ्यक्रम लेने के लिए उपयुक्त नहीं हो। यह अपरिवर्तनीय बनाना काफी सवाल से बाहर है, और मुझे लगता है कि प्रकार के ज़्यादातर उपयोग होगा उम्मीद उत्परिवर्तन।
अगर ऐसी बात है, तो यह आपके इंटरफेस बदल रहा है कि स्पष्ट करने के लायक हो सकता है। इसके बजाय लौटने एक के IEnumerable<User>(- कुछ हद तक - जिसका मतलब प्रक्षेपण) तुम दोनों हस्ताक्षर और नाम बदलने के लिए चाहते हो सकता है, कुछ इस तरह के साथ छोड़:
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
}
}
फिर, यह एक विशेष रूप से "LINQ-y" समाधान (मुख्य संचालन में) किसी भी अधिक नहीं है - लेकिन यह है कि उचित है, जैसा कि आप वास्तव में नहीं "क्वेरी" कर रहे हैं; आप "अद्यतन करने" कर रहे हैं।