2008-12-08 10 views
52

Units of Measure in F# से प्रेरित, और जोरदार (here) के बावजूद कि आप इसे सी # में नहीं कर पाए, मुझे पता था कि दूसरे दिन मैं किसके साथ खेल रहा हूं।सी # में माप की इकाइयां - लगभग

namespace UnitsOfMeasure 
{ 
    public interface IUnit { } 
    public static class Length 
    { 
     public interface ILength : IUnit { } 
     public class m : ILength { } 
     public class mm : ILength { } 
     public class ft : ILength { } 
    } 
    public class Mass 
    { 
     public interface IMass : IUnit { } 
     public class kg : IMass { } 
     public class g : IMass { } 
     public class lb : IMass { } 
    } 

    public class UnitDouble<T> where T : IUnit 
    { 
     public readonly double Value; 
     public UnitDouble(double value) 
     { 
      Value = value; 
     } 
     public static UnitDouble<T> operator +(UnitDouble<T> first, UnitDouble<T> second) 
     { 
      return new UnitDouble<T>(first.Value + second.Value); 
     } 
     //TODO: minus operator/equality 
    } 
} 

उदाहरण उपयोग:

var a = new UnitDouble<Length.m>(3.1); 
var b = new UnitDouble<Length.m>(4.9); 
var d = new UnitDouble<Mass.kg>(3.4); 
Console.WriteLine((a + b).Value); 
//Console.WriteLine((a + c).Value); <-- Compiler says no 

अगले कदम को लागू करने के रूपांतरण (स्निपेट) कोशिश कर रहा है:

public interface IUnit { double toBase { get; } } 
public static class Length 
{ 
    public interface ILength : IUnit { } 
    public class m : ILength { public double toBase { get { return 1.0;} } } 
    public class mm : ILength { public double toBase { get { return 1000.0; } } } 
    public class ft : ILength { public double toBase { get { return 0.3048; } } } 
    public static UnitDouble<R> Convert<T, R>(UnitDouble<T> input) where T : ILength, new() where R : ILength, new() 
    { 
     double mult = (new T() as IUnit).toBase; 
     double div = (new R() as IUnit).toBase; 
     return new UnitDouble<R>(input.Value * mult/div); 
    } 
} 

(मैं, स्थिर का उपयोग करके वस्तुओं instantiating से बचने के लिए पसंद किया है, लेकिन जैसा कि हम सभी जानते हैं can't declare a static method in an interface) आप यह कर सकते हैं:

var e = Length.Convert<Length.mm, Length.m>(c); 
var f = Length.Convert<Length.mm, Mass.kg>(d); <-- but not this 

जाहिर है, एफ # इकाइयों के माप की तुलना में इसमें एक अंतर छेद है (मैं आपको इसे काम करने दूँगा)।

ओह, सवाल यह है: आप इसके बारे में क्या सोचते हैं? क्या इसका उपयोग करने लायक है? क्या किसी और ने पहले ही बेहतर किया है? इस विषय क्षेत्र में रुचि रखने वाले लोगों के लिए

अद्यतन, here एक ही माप की विभिन्न इकाइयों के लिए अलग वर्ग का उपयोग करते हुए एक समाधान की एक अलग तरह की चर्चा कर

+2

Frink कैलकुलेटर और Frink प्रोग्रामिंग भाषा पर एक नजर डालें। –

+2

मुझे आश्चर्य है कि किसी ने कक्षा संपत्ति मूल्यों के गुणों के साथ सी # में इकाइयों से संपर्क किया है। – ja72

+0

फ़्रिंक इस प्रकार की समस्या के लिए बम है। –

उत्तर

14

1997 से एक कागज लिए लिंक (सी # के लिए नहीं विशेष रूप से) है (उदाहरण के लिए, सेमी, मिमी, और लंबाई के लिए फीट) अजीब लगता है। .NET फ्रेमवर्क के दिनांक समय और समयावधि वर्गों के आधार पर, मैं कुछ इस तरह उम्मीद करेंगे:

Length length  = Length.FromMillimeters(n1); 
decimal lengthInFeet = length.Feet; 
Length length2  = length.AddFeet(n2); 
Length length3  = length + Length.FromMeters(n3); 
+2

यह मेरा पहला वृत्ति भी था। इसके साथ नकारात्मकता यह है कि आपको ऑपरेटरों को स्पष्ट रूप से परिभाषित करना होगा जो इकाइयों के सभी क्रमिकताओं को जोड़ते हैं। जब आप वेग (लंबाई/टाइमस्पैन) जैसे विभिन्न इकाइयों को एक साथ जोड़ना शुरू करते हैं तो यह अधिक जटिल हो जाता है, जहां आप बहुत अधिक संख्या में उन XXXXX रूपांतरणों को हाइव करते हैं जिन्हें आपको समर्थन देना होगा। –

39

आप आयामी विश्लेषण गायब हैं। उदाहरण के लिए (उत्तर आप से जुड़ा हुआ से), एफ # में आप यह कर सकते हैं:

let g = 9.8<m/s^2> 

और यह त्वरण की एक नई इकाई, मीटर और सेकंड से प्राप्त उत्पन्न होगा (आप वास्तव में सी में एक ही बात कर सकते हैं ++ टेम्पलेट का उपयोग कर)।

सी # में, रनटाइम पर आयामी विश्लेषण करना संभव है, लेकिन यह ओवरहेड जोड़ता है और आपको संकलन-समय की जांच का लाभ नहीं देता है। जहां तक ​​मुझे पता है कि सी # में पूर्ण संकलन-समय इकाइयों को करने का कोई तरीका नहीं है।

चाहे यह करने योग्य है, पाठ्यक्रम के आवेदन पर निर्भर करता है, लेकिन कई वैज्ञानिक अनुप्रयोगों के लिए, यह निश्चित रूप से एक अच्छा विचार है। मैं .NET के लिए किसी भी मौजूदा पुस्तकालयों के बारे में नहीं जानता, लेकिन वे शायद मौजूद हैं।

यदि आप रनटाइम पर इसे कैसे करना चाहते हैं, तो विचार यह है कि प्रत्येक मान में स्केलर मान और प्रत्येक मूल इकाई की शक्ति का प्रतिनिधित्व करने वाले पूर्णांक होते हैं।

class Unit 
{ 
    double scalar; 
    int kg; 
    int m; 
    int s; 
    // ... for each basic unit 

    public Unit(double scalar, int kg, int m, int s) 
    { 
     this.scalar = scalar; 
     this.kg = kg; 
     this.m = m; 
     this.s = s; 
     ... 
    } 

    // For addition/subtraction, exponents must match 
    public static Unit operator +(Unit first, Unit second) 
    { 
     if (UnitsAreCompatible(first, second)) 
     { 
      return new Unit(
       first.scalar + second.scalar, 
       first.kg, 
       first.m, 
       first.s, 
       ... 
      ); 
     } 
     else 
     { 
      throw new Exception("Units must match for addition"); 
     } 
    } 

    // For multiplication/division, add/subtract the exponents 
    public static Unit operator *(Unit first, Unit second) 
    { 
     return new Unit(
      first.scalar * second.scalar, 
      first.kg + second.kg, 
      first.m + second.m, 
      first.s + second.s, 
      ... 
     ); 
    } 

    public static bool UnitsAreCompatible(Unit first, Unit second) 
    { 
     return 
      first.kg == second.kg && 
      first.m == second.m && 
      first.s == second.s 
      ...; 
    } 
} 

आप उपयोगकर्ता, आप सामान्य इकाइयों के लिए उपवर्गों जोड़ सकते हैं इकाइयों के मूल्य (एक अच्छा विचार वैसे भी) को बदलने की अनुमति नहीं है:

class Speed : Unit 
{ 
    public Speed(double x) : base(x, 0, 1, -1, ...); // m/s => m^1 * s^-1 
    { 
    } 
} 

class Acceleration : Unit 
{ 
    public Acceleration(double x) : base(x, 0, 1, -2, ...); // m/s^2 => m^1 * s^-2 
    { 
    } 
} 

आप और अधिक विशिष्ट निर्धारित कर सकते हैं सामान्य प्रकारों पर संगत इकाइयों की जांच से बचने के लिए व्युत्पन्न प्रकारों पर ऑपरेटर।

+0

ये, मुझे पता था कि जो गुम था, मुझे आपका समाधान पसंद है, लेकिन जैसा कि आप कहते हैं, यह संकलन समय नहीं है। वैसे भी वोट दें। – Benjol

+0

जब मैं अधिक बुनियादी इकाइयों को जोड़ता हूं तो जटिलता में बढ़ने वाले शुरुआती लोगों को देखना पसंद नहीं करता है। चूंकि आप संकलन समय पर गलत इकाइयों का पता लगाने की क्षमता खो चुके हैं, इसलिए आप एक कदम आगे बढ़ा सकते हैं और प्रत्येक प्रकार के लिए एक अलग फ़ील्ड रखने के बजाय int में स्ट्रिंग या गणना को मैपिंग करने के लिए एक शब्दकोश का उपयोग कर सकते हैं। – Brian

+0

यदि आप एसआई सिस्टम (समय, द्रव्यमान, लंबाई, तापमान, चमकदार तीव्रता, पदार्थ राशि और विद्युत प्रवाह) लेते हैं तो केवल 7 आधार इकाइयां हैं। यदि आप यूनिट को गुणक मान जोड़ते हैं जो एसआई प्रस्तुति के लिए रूपांतरण कारखाना है तो आप एक काफी अच्छा मॉडल प्राप्त कर सकते हैं। –

0

कोडडॉम का उपयोग स्वचालित रूप से इकाइयों के सभी संभावित क्रमिक क्रम उत्पन्न करने के लिए क्यों नहीं करें? मुझे पता है कि यह सबसे अच्छा नहीं है - लेकिन मैं निश्चित रूप से काम करूंगा!

+0

क्या आप कोड जनरेशन के लिए कोडडॉम का उपयोग करने का प्रस्ताव कर रहे हैं? –

0

देखें बू Ometa (जो बू 1.0 के लिए उपलब्ध हो जाएगा): Boo Ometa and Extensible Parsing

+0

लिंक टूटा हुआ प्रतीत होता है। –

+0

लिंक http://bamboo.github.com/2008/08/05/boo-ometa-and-extensible-parsing-I.html –

+0

इसे ठीक किया गया है, क्षमा करें, मैंने इसे जल्द ही नहीं देखा। –

15

आप सांख्यिक प्रकार पर विस्तार विधियों को जोड़ने के उपायों उत्पन्न करने के लिए कर सकता है। यह थोड़ा डीएसएल की तरह लग रहा है चाहते हैं:

var mass = 1.Kilogram(); 
var length = (1.2).Kilometres(); 

यह वास्तव में नेट सम्मेलन नहीं है और सबसे खोज योग्य सुविधा नहीं हो सकता है, तो शायद आप लोग हैं, जो उन्हें पसंद के लिए एक समर्पित नाम स्थान में उन्हें जोड़ना होगा, के रूप में साथ ही अधिक पारंपरिक निर्माण विधियों की पेशकश के रूप में।

3

विचार के लिए धन्यवाद। मैंने सी # में इकाइयों को कई अलग-अलग तरीकों से लागू किया है, जो हमेशा पकड़ते हैं। अब मैं ऊपर चर्चा किए गए विचारों का उपयोग करके एक और बार कोशिश कर सकता हूं। मेरा लक्ष्य उचित आयाम, स्केलिंग और उपयोग करने के लिए प्रतीक यह पता लगाने की

Unit lbf = 4.44822162*N; 
Unit fps = feet/sec; 
Unit hp = 550*lbf*fps 

की तरह और कार्यक्रम के लिए मौजूदा आधार पर नई इकाइयों को परिभाषित करने में सक्षम होना है। अंत में मुझे एक मूल बीजगणित प्रणाली बनाने की आवश्यकता है जो (m/s)*(m*s)=m^2 जैसी चीजों को परिवर्तित कर सके और परिभाषित मौजूदा इकाइयों के आधार पर परिणाम व्यक्त करने का प्रयास करें।

इसके अलावा एक आवश्यकता एक तरीका है कि नई इकाइयों कूटबद्ध किया की जरूरत नहीं है में इकाइयों को क्रमानुसार करने में सक्षम होने की होना चाहिए, लेकिन सिर्फ इस तरह एक XML फ़ाइल में घोषणा की:

<DefinedUnits> 
    <DirectUnits> 
<!-- Base Units --> 
<DirectUnit Symbol="kg" Scale="1" Dims="(1,0,0,0,0)" /> 
<DirectUnit Symbol="m" Scale="1" Dims="(0,1,0,0,0)" /> 
<DirectUnit Symbol="s" Scale="1" Dims="(0,0,1,0,0)" /> 
... 
<!-- Derived Units --> 
<DirectUnit Symbol="N" Scale="1" Dims="(1,1,-2,0,0)" /> 
<DirectUnit Symbol="R" Scale="1.8" Dims="(0,0,0,0,1)" /> 
... 
    </DirectUnits> 
    <IndirectUnits> 
<!-- Composite Units --> 
<IndirectUnit Symbol="m/s" Scale="1"  Lhs="m" Op="Divide" Rhs="s"/> 
<IndirectUnit Symbol="km/h" Scale="1"  Lhs="km" Op="Divide" Rhs="hr"/> 
... 
<IndirectUnit Symbol="hp" Scale="550.0" Lhs="lbf" Op="Multiply" Rhs="fps"/> 
    </IndirectUnits> 
</DefinedUnits> 
+2

यह सुनिश्चित नहीं है कि आपको डाउनवोट क्यों मिला, लेकिन मुझे लगता है कि आप पहिया को फिर से आविष्कार करने की कोशिश करने से शायद F # सीखने से बेहतर होंगे। मैंने अपने प्रश्न को एक ऐसे पेपर के लिंक के साथ अपडेट किया है जो आपको रूचि दे सकता है। रचनात्मक टिप्पणी के लिए – Benjol

+0

धन्यवाद। – ja72

3

यहाँ के साथ मेरी चिंता का विषय है सी #/वीबी में इकाइयों का निर्माण। अगर आपको लगता है कि मैं गलत हूं तो कृपया मुझे सही करें। मेरे द्वारा पढ़े जाने वाले अधिकांश कार्यान्वयन में एक संरचना बनाने में शामिल होना शामिल है जो एक इकाई के साथ मूल्य (int या double) को एकसाथ टुकड़ा करता है। फिर आप इन संरचनाओं के लिए बुनियादी कार्यों (+ - * /, आदि) को परिभाषित करने का प्रयास करते हैं जो खाता इकाई रूपांतरण और स्थिरता को ध्यान में रखते हैं।

मुझे यह विचार बहुत आकर्षक लगता है, लेकिन हर बार जब मैं एक परियोजना के लिए एक बड़ा कदम यह सोचता हूं कि यह प्रतीत होता है। यह एक सब कुछ या कुछ भी सौदा की तरह दिखता है। आप शायद कुछ संख्याओं को इकाइयों में नहीं बदलेंगे; पूरा मुद्दा यह है कि किसी भी अस्पष्टता से बचने के लिए किसी परियोजना के अंदर सभी डेटा उचित रूप से एक इकाई के साथ लेबल किया जाता है। इसका मतलब सामान्य युगल और स्याही का उपयोग करने के लिए अलविदा कहने का मतलब है, प्रत्येक चर को अब "इकाई" या "लंबाई" या "मीटर" के रूप में परिभाषित किया जाता है, आदि। क्या लोग वास्तव में बड़े स्तर पर ऐसा करते हैं? तो यदि आपके पास एक बड़ी सरणी है, तो भी प्रत्येक तत्व को एक इकाई के साथ चिह्नित किया जाना चाहिए। यह स्पष्ट रूप से आकार और प्रदर्शन दोनों ramifications दोनों होगा।

यूनिट तर्क को पृष्ठभूमि में धक्का देने की कोशिश में सभी चतुरता के बावजूद, कुछ बोझिल नोटेशन सी # के साथ अनिवार्य लगता है। एफ # कुछ पीछे के दृश्य जादू करता है जो इकाई तर्क के परेशान कारक को बेहतर बनाता है।

साथ ही, हम कितनी सफलतापूर्वक एक सामान्य डबल की तरह एक यूनिट का इलाज कर सकते हैं जब हम चाहते हैं, सीटीपी या "। वैल्यू" या किसी भी अतिरिक्त नोटेशन का उपयोग करते हुए? जैसे कि nullables के साथ, कोड एक डबल इलाज के लिए जानता है? बस एक डबल की तरह (बेशक अगर आपका डबल?शून्य है तो आपको एक त्रुटि मिलती है)।

+0

हां, बाद में इस चर्चा के लिए कमर, लेकिन यही कारण है कि मुझे लगता है कि कोड कोड लाइब्रेरी के बजाए डेवलपर्स की सहायता के लिए यह मूल भाषा सुविधा होना चाहिए, ताकि संकलित कोड में कोई अबाध शेष न हो। – Jonas

0

मुझे वास्तव में इस स्टैक ओवरफ़्लो प्रश्न और उसके उत्तरों के माध्यम से पढ़ने को पसंद आया।

मैं एक पालतू परियोजना है कि मैं पिछले कुछ वर्षों में बढ़ा दिया है, और हाल ही में शुरू कर दिया है इसे फिर से लिखने और http://ngenericdimensions.codeplex.com

यह कुछ हद तक के कई के समान होता है पर खुला स्रोत करने के लिए इसे जारी किया है इस पृष्ठ के प्रश्न और उत्तर में व्यक्त विचार।

यह मूल रूप से जेनेरिक आयाम बनाने के बारे में है, माप की इकाई और मूल डेटाटाइप सामान्य जेनरेटर्स के रूप में।

उदाहरण के लिए:

Dim myLength1 as New Length(of Miles, Int16)(123) 

एक्सटेंशन के तरीके के कुछ वैकल्पिक उपयोग के साथ यह भी पसंद:

Dim myLength2 = 123.miles 

और

Dim myLength3 = myLength1 + myLength2 
Dim myArea1 = myLength1 * myLength2 

यह संकलन नहीं होगा:

Dim myValue = 123.miles + 234.kilograms 

नई इकाइयों को आपके पुस्तकालयों में बढ़ाया जा सकता है।

ये डेटाटाइप ऐसे संरचनाएं हैं जिनमें केवल 1 आंतरिक सदस्य चर होता है, जिससे उन्हें हल्का बना दिया जाता है।

असल में, ऑपरेटर अधिभार "आयाम" संरचनाओं तक सीमित हैं, ताकि माप की प्रत्येक इकाई को ऑपरेटर ओवरलोड की आवश्यकता न हो।

बेशक, एक बड़ी नकारात्मकता जेनेरिक वाक्यविन्यास की लंबी घोषणा है जिसके लिए 3 डेटाटाइप की आवश्यकता होती है। तो अगर यह आपके लिए एक समस्या है, तो यह आपकी पुस्तकालय नहीं है।

मुख्य उद्देश्य एक संकलन-समय जांच फैशन में इकाइयों के साथ एक इंटरफ़ेस को सजाने में सक्षम होना था।

लाइब्रेरी में बहुत कुछ करने की ज़रूरत है, लेकिन मैं इसे पोस्ट करना चाहता था अगर यह किसी चीज की तलाश में था।

9

अब इस तरह के एक सी # पुस्तकालय मौजूद है: http://www.codeproject.com/Articles/413750/Units-of-Measure-Validator-for-Csharp

यह लगभग एफ # की इकाई के रूप में एक ही सुविधाओं समय सत्यापन संकलन है, लेकिन सी # के लिए। कोर एक एमएसबिल्ड कार्य है, जो कोड को पार करता है और सत्यापन की तलाश करता है।

इकाई की जानकारी टिप्पणियों और विशेषताओं में संग्रहीत की जाती है।

+1

दिलचस्प प्रयास, लेकिन लेखक मानते हैं कि वह परियोजना से असंतुष्ट है और स्क्रैच से फिर से शुरू करने का सुझाव देता है। एक समान पुस्तकालय यहां पाया जा सकता है: https://github.com/InitialForce/UnitsNet – kmote

+0

URL बदल गया है https://github.com/angularsen/UnitsNet – angularsen

8

मैंने हाल ही में Units.NET को GitHub पर और NuGet पर जारी किया।

यह आपको सभी सामान्य इकाइयों और रूपांतरण देता है। यह हल्का वजन है, यूनिट परीक्षण और पीसीएल का समर्थन करता है।

उदाहरण रूपांतरण:

Length meter = Length.FromMeters(1); 
double cm = meter.Centimeters; // 100 
double yards = meter.Yards; // 1.09361 
double feet = meter.Feet; // 3.28084 
double inches = meter.Inches; // 39.3701 
0

आप के बजाय अपने खुद के द्वारा लागू की QuantitySystem इस्तेमाल कर सकते हैं।यह एफ # पर बनाता है और एफ # में यूनिट हैंडलिंग में भारी सुधार करता है। यह अब तक का सबसे अच्छा कार्यान्वयन है और सी # परियोजनाओं में इसका उपयोग किया जा सकता है।

http://quantitysystem.codeplex.com

संबंधित मुद्दे