ධාවන වේලාවේදී පමණක් දන්නා වර්ග පරාමිතියක් සහිත සාමාන්ය ක්රමයක් ඇමතීමෙන් dynamic
පරාවර්තන API වෙනුවට වර්ගයක් භාවිතා කිරීමෙන් බොහෝ සරල කළ හැකිය .
මෙම තාක්ෂණය භාවිතා කිරීම සඳහා වර්ගය සත්ය වස්තුවෙන් දැනගත යුතුය ( Type
පන්තියේ අවස්ථාවක් පමණක් නොවේ ). එසේ නොමැතිනම්, ඔබට එම වර්ගයේ වස්තුවක් නිර්මාණය කිරීමට හෝ සම්මත පරාවර්තන API විසඳුම භාවිතා කිරීමට සිදුවේ . Activator.CreateInstance ක්රමය භාවිතා කිරීමෙන් ඔබට වස්තුවක් නිර්මාණය කළ හැකිය .
ඔබට සාමාන්ය ක්රමයක් ඇමතීමට අවශ්ය නම්, “සාමාන්ය” භාවිතයේදී එහි වර්ගය අනුමාන කළ හැකිව තිබුනේ නම්, එය හුදෙක් නොදන්නා වර්ගයේ වස්තුව වාත්තු කිරීම සඳහා පැමිණේ dynamic
. මෙන්න උදාහරණයක්:
class Alpha { }
class Beta { }
class Service
{
public void Process<T>(T item)
{
Console.WriteLine("item.GetType(): " + item.GetType()
+ "\ttypeof(T): " + typeof(T));
}
}
class Program
{
static void Main(string[] args)
{
var a = new Alpha();
var b = new Beta();
var service = new Service();
service.Process(a); // Same as "service.Process<Alpha>(a)"
service.Process(b); // Same as "service.Process<Beta>(b)"
var objects = new object[] { a, b };
foreach (var o in objects)
{
service.Process(o); // Same as "service.Process<object>(o)"
}
foreach (var o in objects)
{
dynamic dynObj = o;
service.Process(dynObj); // Or write "service.Process((dynamic)o)"
}
}
}
මෙන්න මෙම වැඩසටහනේ ප්රතිදානය:
item.GetType(): Alpha typeof(T): Alpha
item.GetType(): Beta typeof(T): Beta
item.GetType(): Alpha typeof(T): System.Object
item.GetType(): Beta typeof(T): System.Object
item.GetType(): Alpha typeof(T): Alpha
item.GetType(): Beta typeof(T): Beta
Process
සම්මත සම්මත තර්කයෙහි සත්ය වර්ගය ( GetType()
ක්රමය භාවිතා කිරීමෙන් ) සහ සාමාන්ය පරාමිතියේ වර්ගය ( typeof
ක්රියාකරු භාවිතා කිරීමෙන් ) ලියන සාමාන්ය උදාහරණ ක්රමයකි .
වස්තු තර්කය dynamic
ටයිප් කිරීමට වාත්තු කිරීමෙන්, ධාවන කාලය තෙක් පරාමිතිය සැපයීම කල් දැමුවෙමු. වූ විට Process
ක්රමය සමග හැඳින්වේ dynamic
තර්කය නම් සම්පාදකවරයා මෙම තර්කය වර්ගය ගැන සැලකිලිමත් වෙන්නේ නැහැ. සම්පාදකයා විසින් ජනනය කරන කේතයක් ක්රියාත්මක වන වේලාවේදී සම්මත සම්මත තර්ක (පරාවර්තනය භාවිතා කරමින්) පරීක්ෂා කර ඇමතීමට හොඳම ක්රමය තෝරන්න. මෙන්න ඇත්තේ මෙම එක් සාමාන්ය ක්රමයක් පමණි, එබැවින් එය නිසි ආකාරයේ පරාමිතියක් සමඟ ආයාචනය කරයි.
මෙම උදාහරණයේ දී, ප්රතිදානය ඔබ ලියා ඇති ආකාරයටම වේ:
foreach (var o in objects)
{
MethodInfo method = typeof(Service).GetMethod("Process");
MethodInfo generic = method.MakeGenericMethod(o.GetType());
generic.Invoke(service, new object[] { o });
}
ගතික වර්ගයක් සහිත අනුවාදය අනිවාර්යයෙන්ම කෙටි හා ලිවීමට පහසුය. මෙම ශ්රිතය කිහිප වතාවක් ඇමතීමේ ක්රියාකාරිත්වය ගැනද ඔබ කරදර නොවිය යුතුය. එකම වර්ගයේ තර්ක ඉදිරි ඇමතුමක් වේගවත් ස්තුති කළ යුතු ගබඩා DLR දී යාන්ත්රණයක්. ඇත්ත වශයෙන්ම, ඔබට නියෝජිතයින් හැඹිලිගත කරන කේතයක් ලිවිය හැකිය, නමුත් dynamic
වර්ගය භාවිතා කිරීමෙන් ඔබට මෙම හැසිරීම නොමිලේ ලැබේ.
ඔබට ඇමතීමට අවශ්ය සාමාන්ය ක්රමයට පරාමිතිගත වර්ගයක තර්කයක් නොමැති නම් (එබැවින් එහි වර්ග පරාමිතිය අනුමාන කළ නොහැක) එවිට ඔබට පහත දැක්වෙන උදාහරණයේ දී මෙන් සාමාන්ය ක්රමයේ ආයාචනය උපකාරක ක්රමයකින් ඔතා ගත හැකිය:
class Program
{
static void Main(string[] args)
{
object obj = new Alpha();
Helper((dynamic)obj);
}
public static void Helper<T>(T obj)
{
GenericMethod<T>();
}
public static void GenericMethod<T>()
{
Console.WriteLine("GenericMethod<" + typeof(T) + ">");
}
}
වර්ගයේ ආරක්ෂාව වැඩි කිරීම
dynamic
පරාවර්තන ඒපීඅයි භාවිතා කිරීම වෙනුවට ආදේශකයක් ලෙස වස්තුව භාවිතා කිරීම ඇත්තෙන්ම විශිෂ්ට දෙය නම්, ඔබ ක්රියාත්මක වන තෙක් ඔබ නොදන්නා මෙම විශේෂිත වර්ගයේ සංයුක්ත කාලය පරීක්ෂා කිරීම පමණක් ඔබට අහිමි වීමයි. වෙනත් තර්ක සහ ක්රමයේ නම සම්පාදකයා විසින් සුපුරුදු පරිදි ස්ථිතිකව විශ්ලේෂණය කරනු ලැබේ. ඔබ තවත් තර්ක ඉවත් කිරීම හෝ එකතු කිරීම, ඒවායේ වර්ග වෙනස් කිරීම හෝ ක්රමයේ නම නැවත නම් කිරීම මඟින් ඔබට සම්පාදක කාල දෝෂයක් ලැබෙනු ඇත. ඔබ ක්රමයේ නම නූලක් Type.GetMethod
ලෙසත්, වස්තු අරාව ලෙස තර්ක කළහොත්ත් මෙය සිදු නොවේ MethodInfo.Invoke
.
සම්පාදනය කරන වේලාවේදී (අදහස් දැක්වූ කේතය) සහ වෙනත් ධාවන වේලාවේදී සමහර දෝෂ හඳුනාගත හැකි ආකාරය නිරූපණය කරන සරල උදාහරණයකි. කුමන ක්රමය ඇමතිය යුතුද යන්න විසඳීමට ඩීඑල්ආර් උත්සාහ කරන ආකාරය ද එය පෙන්වයි.
interface IItem { }
class FooItem : IItem { }
class BarItem : IItem { }
class Alpha { }
class Program
{
static void Main(string[] args)
{
var objects = new object[] { new FooItem(), new BarItem(), new Alpha() };
for (int i = 0; i < objects.Length; i++)
{
ProcessItem((dynamic)objects[i], "test" + i, i);
//ProcesItm((dynamic)objects[i], "test" + i, i);
//compiler error: The name 'ProcesItm' does not
//exist in the current context
//ProcessItem((dynamic)objects[i], "test" + i);
//error: No overload for method 'ProcessItem' takes 2 arguments
}
}
static string ProcessItem<T>(T item, string text, int number)
where T : IItem
{
Console.WriteLine("Generic ProcessItem<{0}>, text {1}, number:{2}",
typeof(T), text, number);
return "OK";
}
static void ProcessItem(BarItem item, string text, int number)
{
Console.WriteLine("ProcessItem with Bar, " + text + ", " + number);
}
}
මෙහිදී අපි නැවතත් යම් ක්රමයක් ක්රියාත්මක කරන්නේ තර්කය dynamic
වර්ගයට දමමිනි. පළමු තර්කයේ වර්ගය සත්යාපනය කිරීම පමණක් ධාවන කාලයට කල් දමනු ලැබේ. ඔබ අමතන ක්රමයේ නම නොපවතින නම් හෝ වෙනත් තර්ක අවලංගු නම් (වැරදි තර්ක ගණනක් හෝ වැරදි වර්ග) ඔබට සම්පාදක දෝෂයක් ලැබෙනු ඇත.
ඔබ dynamic
තර්කය ක්රමයකට යොමු කළ විට මෙම ඇමතුම මෑතකදී බැඳී ඇත. ක්රමයේ අධි බර විභේදනය ක්රියාත්මක වන වේලාවේදී සිදු වන අතර හොඳම අධි බර තෝරා ගැනීමට උත්සාහ කරයි. එබැවින් ඔබ වර්ගයේ ProcessItem
වස්තුවක් සමඟ ක්රමයට ආයාචනා කරන්නේ නම්, ඔබ BarItem
ඇත්ත වශයෙන්ම සාමාන්ය නොවන ක්රමය ලෙස හඳුන්වනු ඇත, මන්ද එය මෙම වර්ගයට වඩා හොඳ ගැලපීමක් වන බැවිනි. කෙසේ වෙතත්, ඔබ Alpha
වර්ගයේ තර්කයක් සම්මත කරන විට ඔබට ධාවන කාල දෝෂයක් ලැබෙනු ඇත, මන්ද මෙම වස්තුව හැසිරවිය හැකි ක්රමයක් නොමැති නිසාය (සාමාන්ය ක්රමයකට අවහිරතා ඇති where T : IItem
අතර Alpha
පන්තිය මෙම අතුරු මුහුණත ක්රියාත්මක නොකරයි). නමුත් සමස්ත කාරණය එයයි. මෙම ඇමතුම වලංගු බවට තොරතුරු සම්පාදකයා සතුව නොමැත. ක්රමලේඛකයෙකු ලෙස ඔබ මෙය දන්නා අතර මෙම කේතය දෝෂයකින් තොරව ක්රියාත්මක වන බවට වග බලා ගත යුතුය.
ආපසු එන වර්ගය ගොචා
ඔබ ගතික වර්ගය ක පරාමිතිය සමඟ-අඩුව නොවන ක්රමය ඉල්ලා විට, සිය ආපසු වර්ගය බොහෝ විට කරනු විය dynamic
ද . එබැවින් ඔබ පෙර උදාහරණය මෙම කේතයට වෙනස් කළහොත්:
var result = ProcessItem((dynamic)testObjects[i], "test" + i, i);
එවිට ප්රති result ල වස්තුවේ වර්ගය වනු ඇත dynamic
. මෙයට හේතුව සම්පාදකයා සැමවිටම හඳුන්වන්නේ කුමන ක්රමයද යන්නයි. ශ්රිත ඇමතුමේ ආපසු පැමිණීමේ වර්ගය ඔබ දන්නේ නම්, ඔබ එය ව්යංගයෙන් අවශ්ය වර්ගයට පරිවර්තනය කළ යුතුය, එවිට ඉතිරි කේතය ස්ථිතිකව ටයිප් කරනු ලැබේ:
string result = ProcessItem((dynamic)testObjects[i], "test" + i, i);
වර්ගය නොගැලපේ නම් ඔබට ධාවන කාල දෝෂයක් ලැබෙනු ඇත.
ඇත්ත වශයෙන්ම, ඔබ පෙර උදාහරණයේ ප්රති result ල අගය ලබා ගැනීමට උත්සාහ කළහොත් දෙවන ලූප් පුනරාවර්තනයේදී ඔබට ධාවන කාල දෝෂයක් ලැබෙනු ඇත. මෙයට හේතුව ඔබ අවලංගු ශ්රිතයක ප්රතිලාභ අගය සුරැකීමට උත්සාහ කිරීමයි.